Определение переменной с или без экспорта - PullRequest
831 голосов
/ 21 июля 2009

Для чего export? 1002 *

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

export name=value

и

name=value

Ответы [ 14 ]

919 голосов
/ 21 июля 2009

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

То есть

export name=value

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

name=value

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

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

220 голосов
/ 21 июля 2009

Чтобы проиллюстрировать, что говорят другие ответы:

$ 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$ 
67 голосов
/ 21 июля 2009

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

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

55 голосов
/ 12 февраля 2014

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

  • Sub shells будет иметь доступ ко всем переменным от родителя, независимо от их экспортированного состояния.
  • Sub процессы будут только см. Экспортированные переменные.

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

$ 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, поэтому для выполнения этой команды больше ничего не осталось.

28 голосов
/ 24 апреля 2013

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
    

Итак, теперь должно быть так же ясно, как летнее солнце! Спасибо Брэйну Агнью, Александру и Уильяму Пруселлу.

10 голосов
/ 21 июля 2009

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

9 голосов
/ 10 февраля 2016

Следует отметить, что вы можете экспортировать переменную, а затем изменить значение. Измененное значение переменной будет доступно дочерним процессам. После того, как экспорт был установлен для переменной, вы должны сделать export -n <var>, чтобы удалить свойство.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
7 голосов
/ 19 июня 2015

Как вы, возможно, уже знаете, 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 - это внутренняя переменная. Поскольку Bash - это не просто интерактивная оболочка, это фактически интерпретатор сценариев, как и любой другой интерпретатор (например, Python), он способен хранить собственный набор переменных. Следует отметить, что Bash (в отличие от Python) поддерживает только строковые переменные.

Обозначение для определения переменных Bash: name=value. Эти переменные остаются внутри Bash и не имеют ничего общего с переменными среды, которые хранятся в операционной системе.

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

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

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


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

  • export используется для установки переменной среды в операционной системе. Эта переменная будет доступна всем дочерним процессам, созданным текущим процессом Bash, когда-либо после этого.
  • Обозначение переменной bash (name = value) используется для установки локальных переменных, доступных только текущему процессу bash
  • Обозначение переменной Bash с префиксом другой команды создает переменную среды только для области действия этой команды.
5 голосов
/ 22 сентября 2017

принятый ответ подразумевает это, но я хотел бы сделать явное соединение со встроенными командами оболочки:

Как уже упоминалось, 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 голосов
/ 22 июля 2009

Вот еще один пример:

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 '...'!

Дополнительные примеры см .:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...