Определение переменной с экспортом или без него
Вопрос: Каково назначение команды export
в Bash?
Я хочу разобраться в назначении команды export
в Bash. В чем разница между следующими двумя командами?
export name=value
и
name=value
Как они влияют на переменные окружения и область видимости?
5 ответ(ов)
Команда export
делает переменную доступной для дочерних процессов.
Это означает, что
export name=value
обозначает, что переменная name
доступна для любого процесса, который вы запускаете из данного процесса оболочки. Если вы хотите, чтобы процесс использовал эту переменную, используйте export
и запускайте процесс из этой оболочки.
name=value
означает, что область видимости переменной ограничивается текущей оболочкой, и она недоступна для других процессов. Вы бы использовали это, например, для переменных цикла, временных переменных и т. д.
Важно отметить, что экспорт переменной не делает её доступной для родительских процессов. То есть указание и экспорт переменной в запущенном процессе не сделает её доступной в процессе, который его запустил.
Для иллюстрации того, о чем говорится в других ответах:
$ export foo="Привет, мир"
$ bar="До свидания"
$ echo $foo
Привет, мир
$ echo $bar
До свидания
$ bash
bash-3.2$ echo $foo
Привет, мир
bash-3.2$ echo $bar
bash-3.2$
Вопрос: Как правильно использовать export
и переменные в Bash?
Ответ: В Bash использование export NAME=value
необходимо для переменных и настроек, которые должны иметь значение в дочерних процессах. В то время как NAME=value
предназначено для временных или локальных переменных, которые действуют только в текущем процессе оболочки.
Более подробно:
- Команда
export
помечает имя переменной в окружении, которое копируется в дочерние процессы и их дочерние процессы при создании. Учтите, что ни имя, ни значение никогда не копируются обратно из дочернего процесса в основной.
Распространенные ошибки:
Ошибка с пробелами: Если поставить пробелы вокруг знака равенства, Bash выдаст ошибку:
$ export FOO = "bar" bash: export: `=': not a valid identifier
Только экспортированная переменная видна в дочернем процессе:
$ 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
Только экспортированные переменные становятся частью окружения:
$ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB" BOB=Bob
Теперь это должно быть так же понятно, как солнечное лето! Спасибо Brain Agnew, alexp и William Prusell.
Это часто обсуждается в сообществах, связанных с Bash, и действительно может вызвать путаницу. Давайте разберёмся.
Есть важное различие между подсистемами (subshells) и подпроцессами (subprocesses) в 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
, и, следовательно, больше нечего выполнять после неё.
Следует отметить, что вы можете экспортировать переменную и затем изменить её значение. Изменённое значение переменной будет доступно для дочерних процессов. Как только переменная была экспортирована, чтобы убрать это свойство, нужно выполнить команду export -n <var>
.
Пример:
$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
В этом примере сначала создаётся переменная K
со значением 1
, затем она экспортируется. После назначения нового значения 2
, это значение доступно в дочерних процессах. Однако, после выполнения команды export -n K
, переменная становится неэкспортируемой, и в дочернем процессе она будет ‘unset’.
Как запросить ввод Yes/No/Cancel в скрипте оболочки Linux?
Как использовать 'grep' для непрерывного потока?
Почему не удается изменить директорию с помощью "cd" в скрипте?
Как изменить цвет вывода echo в Linux
Как работает "cat << EOF" в bash?