Что такое export
для?
В чем разница между:
export name=value
и
name=value
Что такое export
для?
В чем разница между:
export name=value
и
name=value
export
делает переменную доступной для подпроцессов.
То есть
export name=value
означает, что имя переменной доступно для любого процесса, который вы запускаете из этого процесса оболочки. Если вы хотите, чтобы процесс использовал эту переменную, используйте export
и запустите процесс из этой оболочки.
name=value
означает, что область переменных ограничена оболочкой и недоступна для любого другого процесса. Вы использовали бы это для (скажем) переменных цикла, временных переменных и т.д.
Важно отметить, что экспорт переменной не делает ее доступной для родительских процессов. То есть, указание и экспорт переменной в порожденном процессе не делает ее доступной в процессе ее запуска.
Чтобы проиллюстрировать, что говорят другие ответы:
$ 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$
Другие ответили, что экспорт делает переменную доступной для подоболочек, и это правильно, но просто побочный эффект. Когда вы экспортируете переменную, она помещает эту переменную в среду текущей оболочки (т.е. оболочка вызывает putenv (3) или setenv (3)). Окружение процесса наследуется через exec, делая переменную видимой в подоболочках.
Редактировать (с перспективой на 5 лет): это глупый ответ. Цель "экспорта" состоит в том, чтобы заставить переменные "находиться в среде последующих выполняемых команд", являются ли эти команды субхолмами или подпроцессами. Наивная реализация заключалась бы в том, чтобы просто поместить переменную в среду оболочки, но это сделало бы невозможным реализацию export -p
.
Было сказано, что не нужно экспортировать в bash при нерестах подоболочек, в то время как другие говорят прямо противоположное. Важно отметить разницу между подоболочками (те, которые создаются ()
, ``
, $()
или циклы) и подпроцессы (процессы, вызываемые по имени, например, буквальный bash
, появляющийся в вашем script). Подсечки будут иметь доступ ко всем переменным от родителя, независимо от их экспортируемого состояния. С другой стороны, подпроцессы будут только видеть экспортированные переменные. Что общего в этих двух конструктах, так это то, что они не могут передавать переменные обратно в родительскую оболочку.
$ 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
, поэтому для выполнения этой команды ничего не осталось.
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
Итак, теперь это должно быть так ясно, как летнее солнце! Благодаря Brain Agnew, alexp и William Prusell.
export
сделает эту переменную доступной для всех оболочек, forked из текущей оболочки.
Следует отметить, что вы можете экспортировать переменную, а затем изменить значение. Измененное значение переменной будет доступно дочерним процессам. После того как экспорт был установлен для переменной, вы должны сделать export -n <var>
, чтобы удалить свойство.
$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
Как вы уже знаете, 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 является не только интерактивной оболочкой, но и интерпретатором script, как и любой другой интерпретатор (например, Python), он способен хранить свой собственный набор переменных. Следует отметить, что Bash (в отличие от Python) поддерживает только строковые переменные.
Обозначение для определения переменных Bash name=value
. Эти переменные остаются внутри Bash и не имеют ничего общего с переменными среды, хранящимися в операционной системе.
Подробнее о Параметры оболочки (включая переменные)
Также стоит отметить, что согласно справочному руководству Bash:
Среда для любой простой команды или функции может быть дополнена временно путем префикса его назначением параметров, как описано в Параметры оболочки. Эти утверждения присваивания влияют только на окружение, видимое этой командой.
Подводя итог:
export
используется для установки переменной среды в операционной системе. Эта переменная будет доступна для всех дочерних процессов, созданных с помощью текущего процесса Bash.принятый ответ подразумевает это, но я хотел бы сделать явным связь с встроенными оболочками оболочки:
Как уже упоминалось, 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
Вот еще один пример:
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 '...'!
Дальнейшие примеры см. ниже:
bash -hackers.org/wiki/doku.php/scripting/processtree
Просто чтобы показать разницу между экспортируемой переменной, находящейся в среде (env), и неэкспортируемой переменной, не находящейся в среде:
Если я это сделаю:
$ MYNAME=Fred
$ export OURNAME=Jim
тогда в env появляется только $OURNAME. Переменная $MYNAME отсутствует в env.
$ env | grep NAME
OURNAME=Jim
но переменная $MYNAME существует в оболочке
$ echo $MYNAME
Fred
Два из создателей UNIX, Брайан Керниган и Роб Пайк объясняют это в своей книге "Окружающая среда программирования UNIX". Google для названия, и вы легко найдете версию в формате pdf.
Они обращаются к переменным оболочки в разделе 3.6 и фокусируются на использовании команды export
в конце этого раздела:
Если вы хотите сделать значение переменной доступной в под-оболочках, следует использовать команду экспорта оболочки. (Вы можете подумать, почему нет способа экспортировать значение переменной из под-оболочки в ее родительскую).
Хотя явно не упоминается в обсуждении, нет необходимости использовать экспорт при нерестах подоболочки изнутри bash, поскольку все переменные копируются в дочерний процесс.
По умолчанию переменные, созданные в script, доступны только текущей оболочке; дочерние процессы (суб-оболочки) не будут иметь доступ к значениям, которые были установлены или изменены. Разрешая дочерним процессам видеть значения, требуется использовать команду export.