12

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

12

Вопрос: Каково назначение команды export в Bash?

Я хочу разобраться в назначении команды export в Bash. В чем разница между следующими двумя командами?

export name=value

и

name=value

Как они влияют на переменные окружения и область видимости?

5 ответ(ов)

13

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

Это означает, что

export name=value

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

name=value

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

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

3

Для иллюстрации того, о чем говорится в других ответах:

$ export foo="Привет, мир"
$ bar="До свидания"

$ echo $foo
Привет, мир
$ echo $bar
До свидания

$ bash
bash-3.2$ echo $foo
Привет, мир
bash-3.2$ echo $bar

bash-3.2$
0

Вопрос: Как правильно использовать 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.

0

Это часто обсуждается в сообществах, связанных с 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, и, следовательно, больше нечего выполнять после неё.

0

Следует отметить, что вы можете экспортировать переменную и затем изменить её значение. Изменённое значение переменной будет доступно для дочерних процессов. Как только переменная была экспортирована, чтобы убрать это свойство, нужно выполнить команду 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’.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь