Если процессы наследуют родительскую среду, зачем нам экспорт?

72

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

Однако я также читал здесь и здесь, что «Процессы наследуют свое окружение от своего родителя (процесс, который их запустил)».

Если это так, зачем нам это нужно export? Чего мне не хватает?

Переменные оболочки не являются частью среды по умолчанию? В чем разница?

Амелио Васкес-Рейна
источник

Ответы:

75

Вы предполагаете, что переменные оболочки находятся в среде . Это неверно Команда export- это то, что определяет имя, которое должно быть в среде вообще. Таким образом:

a=1 b=2
export b

в результате текущая оболочка знает, что она $aрасширяется до 1 и $bдо 2, но подпроцессам ничего не будет известно о том, aчто она не является частью среды (даже в текущей оболочке).

Некоторые полезные инструменты:

  • set: Полезно для просмотра параметров текущей оболочки, экспортировано или нет
  • set -k: Устанавливает назначенные аргументы в среде. Рассмотреть возможностьf() { set -k; env; }; f a=1
  • set -a: Говорит оболочке поместить любое имя, которое устанавливается в окружение. Как положить exportперед каждым заданием. Полезно для .envфайлов, как в set -a; . .env; set +a.
  • export: Говорит оболочке ввести имя в окружение. Экспорт и назначение - это две совершенно разные операции.
  • env: Как внешняя команда, envможет рассказать вам только о унаследованной среде, поэтому она полезна для проверки работоспособности.
  • env -i: Полезно для очистки среды перед запуском подпроцесса.

Альтернативы export:

  1. name=val command # Назначение перед командой экспортирует это имя в команду.
  2. declare/local -x name # Экспортирует имя, особенно полезно в функциях оболочки, когда вы хотите избежать раскрытия имени вне области видимости.
  3. set -a # Экспортирует каждое следующее назначение.
Кодзиро
источник
3
set -kЭто так, что можно использовать cmd ENVVAR=valueвместо ENVVAR=value cmd, это не будет работать в вашем примере, если не set -kбыло выполнено до вызова f. Кроме того, не многие оболочки поддерживают его в настоящее время и только для обратной совместимости с оболочкой Bourne. В оболочке Bourne (или Korn) это не сработало бы для функций. И поскольку он влияет на синтаксический анализ оболочки, он должен действовать, когда оболочка читает код, который использует его там.
Стефан
1
Вы также можете упомянутьset -a
Стефан
24

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

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

#!/bin/sh

MYVAR="my cool variable"

echo "Without export:"
printenv | grep MYVAR

echo "With export:"
export MYVAR
printenv | grep MYVAR
Андреас Визе
источник
6

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

$ cat subshell.sh 
#!/usr/bin/env bash
declare | grep -e '^PATH=' -e '^foo='

сравнить

$ cat test.sh 
#!/usr/bin/env bash
export PATH=/bin
export foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test.sh 
PATH=/bin
foo=bar
PATH=/bin
foo=bar

С участием

$ cat test2.sh 
#!/usr/bin/env bash
PATH=/bin
foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test2.sh 
PATH=/bin
foo=bar
PATH=/bin

Поскольку fooоболочка test2.shне экспортируется и никогда не экспортируется, она не была частью среды subshell.shпоследнего запуска.

l0b0
источник