Я только что столкнулся с проблемой, которая показывает мне, что я не ясно о области действия переменных оболочки.
Я пытался использовать bundle install
, это команда Ruby, которая использует значение $GEM_HOME
для выполнения своей работы. Я установил $GEM_HOME
, но команда игнорировала это значение, пока я не использовал export
, как в export GEM_HOME=/some/path
.
Я читал, что это делает переменную как-то «глобальной» (также известной как переменная среды ), но я не понимаю, что это значит. Я знаю о глобальности в программировании, но не в разных программах.
Кроме того, учитывая, что мои установки таких переменных применимы только к текущему сеансу оболочки, как бы я установил их, скажем, для демонизированного процесса?
Какие области видимости могут иметь переменные оболочки?
источник
FOO=bar
, это устанавливает значение для текущего процесса оболочки. Если я затем запускаю программу наподобие (bundle install
), она создает дочерний процесс, к которому нет доступаFOO
. Но если бы я сказалexport FOO=bar
, дочерний процесс (и его потомки) имели бы к нему доступ. Один из них может, в свою очередь, вызватьexport FOO=buzz
изменение значения для его потомков или простоFOO=buzz
изменить значение только для себя. Это примерно так?По крайней мере, под
ksh
иbash
переменные могут иметь три области, а не две, как все остальные ответы в настоящее время говорят.В дополнение к экспортируемой (т. Е. Окружающей среде) переменной и областям неэкспортированных переменных оболочки также существует третий, более узкий, для локальных переменных функции.
Переменные, объявленные в функциях оболочки с
typeset
токеном, видны только внутри функций, в которых они объявлены, и в (под) функциях, вызываемых оттуда.Это
ksh
/bash
код:производит этот вывод:
Как видите, экспортированная переменная отображается из первых трех местоположений, неэкспортированные переменные не отображаются вне текущей оболочки, а локальная переменная функции не имеет значения вне самой функции. Последний тест не показывает значений вообще, это связано с тем, что экспортированные переменные не являются общими для оболочек, то есть они могут быть унаследованы только, а родительская оболочка не может впоследствии влиять на унаследованное значение.
Обратите внимание, что это последнее поведение сильно отличается от Windows, где вы можете использовать системные переменные, которые являются полностью глобальными и общими для всех процессов.
источник
Они ограничены процессом
Другие ответчики помогли мне понять, что область видимости переменных оболочки - это процессы и их потомки .
Когда вы набираете команду, как
ls
в командной строке, вы фактически разветвляете процесс для запускаls
программы. Новый процесс имеет вашу оболочку в качестве родителя.Любой процесс может иметь свои собственные «локальные» переменные, которые не передаются дочерним процессам. Он также может устанавливать переменные окружения, которые есть. Использование
export
создает переменную среды. В любом случае несвязанные процессы (одноранговые узлы оригинала) не увидят переменную; мы контролируем только то, что видят дочерние процессы.Предположим, у вас есть оболочка bash, которую мы будем называть A. Вы вводите
bash
, которая создает дочернюю оболочку bash процесса, которую мы будем называть B. Все, что вы вызываетеexport
в A, все равно будет установлено в B.Теперь, в B, вы говорите
FOO=b
. Произойдет одно из двух:FOO
, он создаст локальную переменную. Дети Б не получат его (если Б не звонитexport
).FOO
, вызванную , он изменит ее для себя и своих потомков-потомков . Дети B увидят значение, присвоенное B. Однако это никак не повлияет на А.Вот быстрое демо.
Все это объясняет мою первоначальную проблему: я установил
GEM_HOME
в своей оболочке, но когда я позвонилbundle install
, это создало дочерний процесс. Поскольку я не использовалexport
, дочерний процесс не получил оболочкиGEM_HOME
.Un-экспорт
Вы можете «отменить экспорт» переменной - предотвратить ее передачу дочерним элементам - используя
export -n FOO
.источник
Лучшее объяснение, которое я могу найти об экспорте, это:
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
Переменная, установленная в подоболочке или дочерней оболочке, видна только той подоболочке, в которой она определена. Экспортированная переменная фактически превращается в переменную окружения. Таким образом, чтобы быть ясным, вы
bundle install
запускаете свою собственную оболочку, которая не видит,$GEM_HOME
если только она не превращена вenvironment
экспортируемую переменную.Вы можете взглянуть на документацию для переменной области здесь:
http://www.tldp.org/LDP/abs/html/subshells.html
источник
FOO=bar
; Вы должны использовать,export
чтобы сделать это один. Вопрос исправлен соответственно.Как и ожидалось, существует иерархия переменных областей.
Среда
Внешняя сфера - это окружающая среда. Это единственная область, управляемая операционной системой, и поэтому она гарантированно существует для каждого процесса. Когда процесс запускается, он получает копию среды своего родителя, после чего они становятся независимыми: изменение среды дочернего элемента не изменяет среду родителя, а изменение среды родителя не изменяет среду уже существующего дочернего элемента.
Переменные оболочки
Оболочки имеют свое собственное понятие переменных. Здесь вещи начинают становиться немного запутанными.
Когда вы присваиваете значение переменной в оболочке, и эта переменная уже существует в среде, переменная среды получает новое значение. Однако, если переменная не находится в среде, она становится переменной оболочки . Переменные оболочки существуют только внутри процесса оболочки, подобно тому, как переменные Ruby существуют только в скрипте Ruby. Они никогда не наследуются дочерними процессами.
Вот где
export
ключевое слово вступает в игру. Он копирует переменную оболочки в среду процесса оболочки, позволяя наследовать дочерние процессы.Локальные переменные
Локальные переменные - это переменные оболочки, ограниченные областями кода, содержащими их. Вы объявляете локальные переменные с помощью
typeset
ключевого слова (переносимый) илиlocal
илиdeclare
(Bash). Как и другие переменные оболочки, локальные переменные не наследуются дочерними процессами. Также локальные переменные не могут быть экспортированы.источник