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

703

Что такое export для?

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

export name=value

и

name=value
Теги:

14 ответов

754
Лучший ответ

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

То есть

export name=value

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

name=value

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

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

  • 86
    В частности, экспорт делает переменную доступной для дочерних процессов через среду.
  • 11
    Я также добавил бы, что если экспорт находится в файле, который вы «источник» (например, имя файла), то он также экспортирует его в вашу рабочую среду.
Показать ещё 7 комментариев
199

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

$ 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$ 
  • 6
    Еще один пример для этого al$ foobar="Whatever" bash
61

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

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

  • 5
    Обратите внимание, что это не совсем так. В bash экспорт действительно добавляет переменную в среду текущей оболочки, но это не относится к dash . Мне кажется, что добавление переменной в среду текущей оболочки является самым простым способом реализации семантики export , но такое поведение не является обязательным.
  • 7
    Я не уверен, что dash с этим связан. Оригинальный плакат спрашивал конкретно о bash .
Показать ещё 4 комментария
43

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

  • 0
    Я никогда не видел цикл, который (сам по себе) создавал подоболочку; OTOH конвейер делает (всегда для частей, отличных от последнего, иногда для последнего в зависимости от вашей оболочки, версии и опций). Фоновая обработка ( & ) также создает подоболочку.
27

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.

  • 1
    +1 за показ общих ошибок
9

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

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
  • 0
    Спасибо, это именно та информация, которую я искал, потому что я увидел скрипт, который использовал переменные окружения, а затем «реэкспортировал» их с новым значением, и мне было интересно, нужно ли это.
  • 0
    @eepp Я только что отредактировал ответ, чтобы исправить эту проблему.
9

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

6

Как вы уже знаете, 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.
  • Bash Обозначение переменной (name = value) используется для установки локальных переменных, доступных только текущему процессу Bash
  • Bash переменная нотация, префиксная другая команда, создает переменную среды только для области действия этой команды.
  • 1
    bash vars не поддерживают столько типов, сколько Python, но имеют строковый, целочисленный и два вида массивов («индексированный» / традиционный и «ассоциативный», который похож на массив awk, perl-хэш или Python dict). Другие оболочки различаются; только строка переносима .
5

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

Как уже упоминалось, 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

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

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

Дальнейшие примеры см. ниже:

2

Два из создателей UNIX, Брайан Керниган и Роб Пайк объясняют это в своей книге "Окружающая среда программирования UNIX". Google для названия, и вы легко найдете версию в формате pdf.

Они обращаются к переменным оболочки в разделе 3.6 и фокусируются на использовании команды export в конце этого раздела:

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

2

Просто чтобы показать разницу между экспортируемой переменной, находящейся в среде (env), и неэкспортируемой переменной, не находящейся в среде:

Если я это сделаю:

$ MYNAME=Fred
$ export OURNAME=Jim

тогда в env появляется только $OURNAME. Переменная $MYNAME отсутствует в env.

$ env | grep NAME
OURNAME=Jim

но переменная $MYNAME существует в оболочке

$ echo $MYNAME
Fred
1

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

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

По умолчанию переменные, созданные в script, доступны только текущей оболочке; дочерние процессы (суб-оболочки) не будут иметь доступ к значениям, которые были установлены или изменены. Разрешая дочерним процессам видеть значения, требуется использовать команду export.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню