Определение переменной с или без экспорта

956

Для чего export?

В чем разница между:

export name=value

а также

name=value
ЭЛЕКТРОДИСТАНЦИОННАЯ СИСТЕМА УПРАВЛЕНИЯ
источник
4
Тангенциально отметим также, что export name=valueэто не портативно. В зависимости от того, что именно вы хотите, попробуйте name=value; export nameпортативное решение.
tripleee

Ответы:

1055

export делает переменную доступной для подпроцессов.

Это,

export name=value

означает, что имя переменной доступно любому процессу, который вы запускаете из этого процесса оболочки. Если вы хотите, чтобы процесс использовал эту переменную, используйте exportи запустите процесс из этой оболочки.

name=value

означает, что область действия переменной ограничена оболочкой и недоступна для любого другого процесса. Вы бы использовали это для (скажем) переменных цикла, временных переменных и т. Д.

Важно отметить, что экспорт переменной не делает ее доступной для родительских процессов. То есть, указание и экспорт переменной в порожденном процессе не делает ее доступной в процессе, который ее запустил.

Брайан Агнью
источник
105
В частности, экспорт делает переменную доступной для дочерних процессов через среду.
Беано
15
Я также добавил бы, что если экспорт находится в файле, который вы «используете» (например, имя файла), то он также экспортирует его в вашу рабочую среду.
rogerdpack
6
@rogerdpack вы не можете сделать это без экспорта? кот> бла \ на = привет \ н. л; эхо $ а; выводит «привет» для меня.
Дэвид Винецкий
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$ 
alxp
источник
9
Еще один пример для этогоal$ foobar="Whatever" bash
Алун
70

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

Изменить (с перспективой на 5 лет): это глупый ответ. Цель «экспорта» состоит в том, чтобы сделать переменные «находящимися в среде последовательно выполняемых команд», независимо от того, являются ли эти команды подоболочками или подпроцессами. Наивной реализацией было бы просто поместить переменную в среду оболочки, но это сделало бы невозможной реализацию export -p.

Уильям Перселл
источник
6
Обратите внимание, что это не совсем так. В bash, export действительно добавляет переменную в среду текущей оболочки, но это не так dash. Мне кажется, что добавление переменной в среду текущей оболочки является самым простым способом реализации семантики export, но такое поведение не является обязательным.
Уильям Перселл
7
Я не уверен, что dashс этим связано. Оригинальный постер спрашивал конкретно о bash.
Морская звезда
14
Вопрос помечен, bashно в равной степени относится к любому варианту оболочки Борна. Быть слишком конкретным и давать ответы, относящиеся только к bashделу, - великое зло.
Уильям Перселл
12
bashэто jQuery оболочки.
Potherca
2
export makes the variable available to subshells, and that is correctЭто очень запутанное использование терминологии. Подоболочкам не нужно exportнаследовать переменные. Подпроцессы делают.
Амит Найду
62

Было сказано, что нет необходимости экспортировать в bash при порождении подоболочек, в то время как другие говорят прямо противоположное. Важно отметить разницу между подоболочками (те, которые созданы (), ``, $()или петля) и подпроцессы (процессы, которые вызываются по имени, например , буквальное 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 () сразу следуют exec (), и поэтому может показаться, что 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(без ;) отношение к порожденному подпроцессу как-то связано с тем, что оболочка origin не имеет к этому никакого отношения 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 и не имеют ничего общего с переменными среды, которые хранятся в операционной системе.

Подробнее о параметрах оболочки (включая переменные)

Также стоит отметить, что, согласно справочнику Bash:

Среду для любой простой команды или функции можно временно дополнить, добавив к ней префиксы с помощью параметров, как описано в разделе Параметры оболочки . Эти операторы присваивания влияют только на среду, видимую этой командой.


Подводя итог:

  • exportиспользуется для установки переменной среды в операционной системе. Эта переменная будет доступна всем дочерним процессам, созданным текущим процессом Bash.
  • Обозначение переменных Bash (name = value) используется для установки локальных переменных, доступных только текущему процессу bash
  • Обозначение переменной Bash с префиксом другой команды создает переменную среды только для области действия этой команды.
progalgo
источник
1
bash vars не поддерживают столько типов, сколько Python, но имеют строковый, целочисленный и два вида массивов («индексированный» / традиционный и «ассоциативный», который похож на массив awk, perl-хэш или Python dict). Другие оболочки различаются; только строка переносима .
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
flow2k
источник
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}"'  

Только с помощью export VARTEST значение VARTEST доступно в sudo bash -c '...'!

Для дальнейших примеров см .:


источник
3

Просто чтобы показать разницу между экспортируемой переменной, находящейся в среде (env), и неэкспортированной переменной, не находящейся в среде:

Если я сделаю это:

$ MYNAME=Fred
$ export OURNAME=Jim

тогда в env появляется только $ OURNAME. Переменная $ MYNAME отсутствует в env.

$ env | grep NAME
OURNAME=Jim

но переменная $ MYNAME существует в оболочке

$ echo $MYNAME
Fred
Будет
источник
3

Два из создателей UNIX, Брайан Керниган и Роб Пайк, объясняют это в своей книге «Среда программирования UNIX». Google для названия, и вы легко найдете PDF-версию.

Они обращаются к переменным оболочки в разделе 3.6 и фокусируются на использовании exportкоманды в конце этого раздела:

Если вы хотите, чтобы значение переменной было доступно в подоболочках, следует использовать команду экспорта оболочки. (Вы можете подумать, почему нет способа экспортировать значение переменной из вложенной оболочки в ее родительский объект).

Дэн Картер
источник
1

По умолчанию переменные, созданные в скрипте, доступны только текущей оболочке; дочерние процессы (вложенные оболочки) не будут иметь доступа к значениям, которые были установлены или изменены. Чтобы дочерние процессы могли видеть значения, необходимо использовать команду экспорта.

Amjad
источник
0

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

Скотт
источник
Пожалуйста, объясните, как то, что вы говорите, кажется, прямо противоречит ответам с примерами выше.
Майк Липперт
Это правильный путь, если вы не хотите, чтобы переменные экспортировались глобально, а были доступны только для подпроцесса! Спасибо.
Jtblin