Визначення змінної з експортом або без нього


955

Для чого export?

Яка різниця між:

export name=value

і

name=value

4
Дотично зауважте також, що export name=valueце не портативно. Залежно від того, що саме ви хочете, спробуйте name=value; export nameзнайти портативне рішення.
tripleee

Відповіді:


1054

export робить змінну доступною для підпроцесів.

Це є,

export name=value

означає, що ім'я змінної доступне для будь-якого процесу, який ви запускаєте з цього процесу оболонки. Якщо ви хочете, щоб процес використовував цю змінну, використовуйте exportта запустіть процес із цієї оболонки.

name=value

означає, що змінна область обмежена оболонкою і не доступна для будь-якого іншого процесу. Ви б використовували це для (скажімо) змінних циклу, тимчасових змінних тощо.

Важливо зазначити, що експорт змінної не робить її доступною для батьківських процесів. Тобто, вказівка ​​та експорт змінної у спареному процесі не робить її доступною у процесі, який її запустив.


105
Зокрема, експорт робить змінну доступною для дочірніх процесів через навколишнє середовище.
Beano

15
Я також додам, що якщо експорт знаходиться у файлі, який ви "джерелом" (наприклад, ім'я файлу), то він також експортує його у ваше робоче середовище.
rogerdpack

6
@rogerdpack не можеш це зробити без експорту? кішка> бла \ на = привіт \ n. бла; ехо $ а; Виходи "привіт" для мене.
David Winiecki

2
Приємно, що це працює навіть без експорту. Тому я думаю, що при пошуку файлу, якщо ви використовуєте експорт, це буде відображено в дочірніх процесах, якщо ви цього не зробите, це просто вплине на локальне середовище bash ...
rogerdpack

19
У цьому є один крайній випадок; name=value command робить змінну доступною в підпроцесі command.
Олівер Чарльворт

254

Щоб проілюструвати, що говорять інші відповіді:

$ foo="Hello, World"
$ echo $foo
Hello, World
$ bar="Goodbye"
$ export foo
$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar

bash-3.2$ 

9
Ще один приклад для цьогоal$ foobar="Whatever" bash
Алун

70

Інші відповіли, що експорт робить змінну доступною для підрозділів, і це правильно, але лише побічний ефект. Коли ви експортуєте змінну, вона розміщує цю змінну в середовищі поточної оболонки (тобто оболонки викликає putenv(3)або setenv(3)).
Середовище процесу успадковується через exec, що робить змінну видимою в підшах.

Правка (з перспективою 5 років): це дурна відповідь. Мета "експорту" полягає в тому, щоб змінні "опинилися в оточенні команд, що виконуються згодом", будь то ці команди підзагортами або підпроцесами. Наївною реалізацією було б просто помістити змінну в середовище оболонки, але це зробило б неможливим реалізацію export -p.


6
Зауважте, що це не зовсім вірно. В bashекспорті дійсно додати змінний в середу поточної оболонки, але це не той випадок з dash. Мені здається, що додавання змінної до середовища поточної оболонки є найпростішим способом реалізації семантики export, але така поведінка не є обов'язковою.
Вільям Перселл

7
Я не впевнений, що dashстосується цього. Оригінальний плакат питав конкретно о bash.
Морська зірка

14
Питання позначено тегами, bashале однаково стосується будь-якого варіанта бурно-оболонки. Бути надмірно конкретним та надавати відповіді, які стосуються лише bash- це велике зло.
Вільям Перселл

12
bash- jQuery оболонки.
Потерка

2
export makes the variable available to subshells, and that is correctЦе дуже заплутане використання термінології. Абонентам не потрібно exportуспадковувати змінні. Підпроцеси роблять.
Аміт Найду

62

Було сказано, що не потрібно експортувати в баш при нерестування передпластів, в той час як інші кажуть, що навпаки. Важливо відзначити різницю між подоболочкі (ті, які створені (), ``, $()або петля) і підпроцеси (процеси, які викликаються по імені, наприклад , буквальне bashпоява в сценарії).

  • Суб- оболонки матимуть доступ до всіх змінних від батьківського, незалежно від стану експорту.
  • Суб процеси будуть тільки побачити експортовані змінні.

Що є спільним для цих двох конструкцій, це те, що жоден не може передати змінні назад до батьківської оболонки.

$ noexport=noexport; export export=export; (echo subshell: $noexport $export; subshell=subshell); bash -c 'echo subprocess: $noexport $export; subprocess=subprocess'; echo parent: $subshell $subprocess
subshell: noexport export
subprocess: export
parent:

Є ще одне джерело плутанини: деякі вважають, що "роздвоєні" підпроцеси - це ті, які не бачать неекспортованих змінних. Зазвичай fork () s одразу слідує за допомогою exec () s, і тому, здавалося б, слід шукати fork (), а насправді це exec (). Ви можете запускати команди без fork (), спочатку за допомогою execкоманди, і процеси, запущені цим методом, також не матимуть доступу до неекспортованих змінних:

$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export

Зауважте, що parent:цього разу ми не бачимо рядок, тому що ми замінили батьківську оболонку execкомандою, тому для виконання цієї команди нічого не залишається.


Я ніколи не бачив циклу, який (сам по собі) створив нижню оболонку; Інший конвеєр OTOH (завжди для частин, відмінних від останнього, іноді для останнього, залежно від вашої оболонки, версії та варіантів). Backgrounding ( &) також створює доподібну оболонку.
dave_thompson_085

Що з цим var=asdf bash -c 'echo $var'чи var=asdf exec bash -c 'echo $var'? Вихід є asdf. ;Робить різницю , якщо помістити після визначення змінної. Яке було б пояснення? Схоже, що var(без ;) стосується породженого підпроцесу якось, оскільки оболонка походження не має нічого спільного з цим. echo $varнічого не друкує, якщо виконано у другому рядку. Але одна підкладка var=asdf bash -c 'echo $var'; echo $varдає asdf\nasdf.
4xy

31

export NAME=value для параметрів і змінних, які мають значення для підпроцесу.

NAME=value для тимчасових або циклічних змінних, приватних для поточного процесу оболонки.

Більш детально, exportпозначає ім'я змінної в середовищі, яке копіюється в підпроцеси та їх підпроцеси при створенні. Жодне ім’я або значення ніколи не копіюється з підпроцесу.

  • Поширена помилка - розмістити пробіл навколо знака рівності:

    $ export FOO = "bar"  
    bash: export: `=': not a valid identifier
  • BПідпроцес бачить лише експортовану змінну ( ):

    $ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
    A is . B is Bob
  • Зміни підпроцесу не змінюють основну оболонку:

    $ export B="Bob"; echo 'B="Banana"' | bash; echo $B
    Bob
  • Змінні, позначені для експорту, мають значення, скопійовані під час створення підпроцесу:

    $ export B="Bob"; echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash &
    [1] 3306
    $ B="Banana"; echo '(sleep 30; echo "Subprocess 2 has B=$B")' | bash 
    Subprocess 1 has B=Bob
    Subprocess 2 has B=Banana
    [1]+  Done         echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash
  • Тільки експортовані змінні стають частиною середовища ( man environ):

     $ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB"
     BOB=Bob

Отже, зараз має бути так ясно, як літнє сонце! Завдяки Мозгові Агнеу, алексупу та Вільяму Пруселлу.


12

export зробить змінну доступною для всіх оболонок, роздвоєних з поточної оболонки.


11

Слід зазначити, що ви можете експортувати змінну і пізніше змінити значення. Змінене значення змінної буде доступне для дочірніх процесів. Після встановлення експорту змінної, ви повинні зробити, export -n <var>щоб видалити властивість.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset

Дякую, це саме та інформація, яку я шукав, тому що я побачив сценарій, який використовував змінні середовища, а потім "реекспортував" їх з новим значенням, і мені було цікаво, чи потрібно.
Майк Ліпперт

8

Як ви вже могли знати, UNIX дозволяє процесам мати набір змінних оточуючих середовищ, які є ключовими / значеннями, і ключові, і значення - це рядки. Операційна система відповідає за збереження цих пар для кожного процесу окремо.

Програма може отримати доступ до змінних середовища через цей UNIX API:

  • char *getenv(const char *name);
  • int setenv(const char *name, const char *value, int override);
  • int unsetenv(const char *name);

Процеси також успадковують змінні середовища від батьківських процесів. Операційна система несе відповідальність за створення копії всіх "envars" в момент створення дочірнього процесу.

Bash , серед інших оболонок, здатний встановлювати свої змінні середовища на запит користувача. Це те, що exportіснує для.

export- команда Bash для встановлення змінної середовища для Bash. Усі змінні, встановлені за допомогою цієї команди, успадковуватимуться всіма процесами, які створив би цей Bash.

Детальніше про довкілля в Баші

Інший вид змінної в Bash - це внутрішня змінна. Оскільки Bash - це не просто інтерактивна оболонка, вона насправді є інтерпретатором сценарію, як і будь-який інший інтерпретатор (наприклад, Python), він здатний зберігати власний набір змінних. Слід зазначити, що Bash (на відміну від Python) підтримує лише рядкові змінні.

Позначення для визначення змінних Bash є name=value. Ці змінні залишаються всередині Bash і не мають нічого спільного зі змінними середовища, що зберігаються в операційній системі.

Детальніше про параметри оболонки (включаючи змінні)

Також варто зазначити, що відповідно до посібника Баша:

Навколишнє середовище для будь-якої простої команди чи функції може бути тимчасово доповнене, додавши її до присвоєння параметрів, як описано в параметрах оболонки . Ці заяви про присвоєння впливають лише на середовище, яке бачить ця команда.


Підводячи підсумки:

  • exportвикористовується для встановлення змінної середовища в операційній системі. Ця змінна буде доступна для всіх дочірніх процесів, створених поточним процесом Bash.
  • Позначення змінної Bash (ім'я = значення) використовується для встановлення локальних змінних, доступних лише для поточного процесу bash
  • Позначення змінної Bash з префіксом іншої команди створює змінну середовища лише для сфери дії цієї команди.

1
bash vars не підтримують стільки типів, як Python, але мають рядковий, цілий і два види масиву ("індексований" / традиційний та "асоціативний", схожий на масив awk, perl хеш чи диктант Python). Інші мушлі відрізняються; тільки рядок є портативним .
dave_thompson_085

7

Загальноприйнятий відповідь має на увазі це, але я хотів би зробити явне з'єднання оболонки вбудованих команд:

Як уже згадувалося, exportзробить змінну доступною як для оболонки, так і для дітей. Якщо exportйого не використовувати, змінна буде доступна лише в оболонці, і лише вбудовані оболонки можуть отримати доступ до неї.

Це є,

tango=3
env | grep tango # prints nothing, since env is a child process
set | grep tango # prints tango=3 - "type set" shows `set` is a shell builtin

3

Ось ще один приклад:

VARTEST="value of VARTEST" 
#export VARTEST="value of VARTEST" 
sudo env | grep -i vartest 
sudo echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}" 
sudo bash -c 'echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"'  

Тільки за допомогою експорту VARTEST значення VARTEST доступне у sudo bash -c '...'!

Для подальших прикладів див:


3

Два із творців UNIX, Брайан Керніган та Роб Пайк, пояснюють це у своїй книзі "Середовище програмування UNIX". Google за назвою, і ви легко знайдете версію PDF.

Вони звертаються до змінних оболонок у розділі 3.6 та зосереджуються на використанні exportкоманди в кінці цього розділу:

Коли ви хочете зробити значення змінної доступною в під оболонках, слід використовувати команду експорту оболонки. (Ви можете подумати про те, чому немає способу експортувати значення змінної з підколі в її батьківський).


2

Просто щоб показати різницю між експортованою змінною, що знаходиться в середовищі (env), і неекспортованою змінною, яка не знаходиться в середовищі:

Якщо я це роблю:

$ MYNAME=Fred
$ export OURNAME=Jim

тоді у env з'являється лише $ OURNAME. Змінна $ MYNAME відсутня в env.

$ env | grep NAME
OURNAME=Jim

але змінна $ MYNAME існує в оболонці

$ echo $MYNAME
Fred

1

За замовчуванням змінні, створені в сценарії, доступні лише для поточної оболонки; дочірні процеси (під оболонки) не матимуть доступу до встановлених або модифікованих значень. Дозвіл дочірніх процесів бачити значення вимагає використання команди експорту.


0

Хоча явно не зазначено в обговоренні, НЕ потрібно використовувати експорт під час нерестування підзаголовка з внутрішньої частини bash, оскільки всі змінні копіюються в дочірній процес.


Поясніть, будь ласка, так, як те, що ви говорите, здається, що прямо суперечить відповідям з прикладів вище
Майк Ліпперт

Це правильний спосіб, якщо ви не хочете експортувати змінні в усьому світі, а доступні лише для підпроцесу! Дякую.
jtblin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.