То, какие объемы окружают переменные, может иметь?

PING (Partimage Не Является Фантомом), живой диск, который создает резервную копию изображений раздела, хотя он вызовет время простоя при создании изображения

43
24.12.2011, 14:11
5 ответов

Они ограничены по объему процессом

Другие отвечающие стороны помогли мне понять, что объем переменной оболочки о процессах и их потомках.

Когда Вы вводите команду как ls на командной строке Вы на самом деле разветвляете процесс для выполнения ls программа. Новый процесс имеет Вашу оболочку как своего родителя.

Любой процесс может иметь свои собственные "локальные" переменные, которые не передаются дочерним процессам. Это может также установить переменные "среды", которые являются. Используя export создает переменную среды. В любом случае несвязанные процессы (коллеги оригинала) не будут видеть переменную; мы только управляем тем, что видят дочерние процессы.

Предположим, что у Вас есть оболочка удара, которую мы назовем A. Вы вводите bash, который создает оболочку удара дочернего процесса, которую мы назовем B. Что-либо Вы звонили export на в A будет все еще установлен в B.

Теперь, в B, Вы говорите FOO=b. Одна из двух вещей произойдет:

  • Если B не получил (от A) названную переменную среды FOO, это создаст локальную переменную. Дети B не получат его (если B не будет звонить export).
  • Если B действительно получал (от A) названную переменную среды FOO, это изменит его для себя и его впоследствии разветвленных детей. Дети B будут видеть значение это присвоенный B. Однако это не будет влиять вообще.

Вот быстрая демонстрация.

FOO=a      # set "local" environment variable
echo $FOO  # 'a'
bash       # forks a child process for the new shell
echo $FOO  # not set
exit       # return to original shell
echo $FOO  # still 'a'

export FOO # make FOO an environment variable
bash       # fork a new "child" shell
echo $FOO  # outputs 'a'
FOO=b      # modifies environment (not local) variable
bash       # fork "grandchild" shell
echo $FOO  # outputs 'b'
exit       # back to child shell
exit       # back to original shell
echo $FOO  # outputs 'a'

Все это объясняет мою исходную проблему: Я установил GEM_HOME в моей оболочке, но когда я звонил bundle install, это создало дочерний процесс. Поскольку я не использовал export, дочерний процесс не получил оболочку GEM_HOME.

Неэкспорт

Можно "не экспортировать" переменную - препятствуют тому, чтобы он был передан детям - при помощи export -n FOO.

export FOO=a   # Set environment variable
bash           # fork a shell
echo $FOO      # outputs 'a'
export -n FOO  # remove environment var for children
bash           # fork a shell
echo $FOO      # Not set
exit           # back up a level
echo $FOO      # outputs 'a' - still a local variable
12
27.01.2020, 19:35
  • 1
    Когда Вы скажете, что "это изменит его для себя и его детей", необходимо разъяснить, что только дети создали после того, как модификация будет видеть измененное значение. –  enzotib 04.01.2012, 23:28
  • 2
    @enzotib - положительная сторона. Обновленный. –  Nathan Long 09.01.2012, 22:18

Процессы организованы как дерево: каждый процесс имеет уникального родителя, кроме init который PID всегда 1 и не имеет никакого родителя.

Создание нового процесса обычно идет через пару fork/execv системные вызовы, где среда дочернего процесса является копией родительского процесса.

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

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

34
27.01.2020, 19:35
  • 1
    ! Хорошо, давайте посмотрим, понимаю ли я это. В оболочке, если я говорю FOO=bar, это устанавливает значение для текущего процесса оболочки. Если я затем запускаю программу как (bundle install), это создает дочерний процесс, который не получает доступ к FOO. Но если я сказал export FOO=bar, дочерний процесс (и его потомки) имел бы доступ к нему. Один из них мог, в свою очередь, звонить export FOO=buzz изменить значение для его потомков, или просто FOO=buzz изменить значение только для себя. Это о праве? А-ч –  Nathan Long 24.12.2011, 14:17
  • 2
    @NathanLong, Это не точно это: во всех современных оболочках или экспортируется переменная (и таким образом, любое изменение в значении отражается в среде потомков), или не экспортировал (подразумевать, что переменная не находится в среде). В частности, если переменная уже находится в среде, когда оболочка запускается, она экспортируется. –  Gilles 'SO- stop being evil' 24.12.2011, 18:02
  • 3
    , я был немного смущен предложением, "если ребенок изменяет значение переменной, измененное значение только видимо к нему и все процессы, созданные после того изменения". Это было бы более корректно для высказывания "... видимый ему и все его порожденные процессы, созданные после того изменения" – другие дети родительского процесса, даже запущенные после дочернего процесса, не затронуты. –  Jaan 25.11.2015, 20:20

По крайней мере, под ksh и bash, переменные могут иметь три объема, не два как все остающиеся ответы в настоящее время говорят.

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

Переменные, объявленные в оболочке, функционируют с typeset маркер только видим в функциях, которыми они объявляются в и в (sub) функции, вызванные оттуда.

Это ksh / bash код:

# Create a shell script named /tmp/show that displays the scoped variables values.    
echo 'echo [$environment] [$shell] [$local]' > /tmp/show
chmod +x /tmp/show

# Function local variable declaration
function f
{
    typeset local=three
    echo "in function":
    . /tmp/show 
}

# Global variable declaration
export environment=one

# Unexported (i.e. local) variable declaration
shell=two

# Call the function that creates a function local variable and
# display all three variable values from inside the function
f

# Display the three values from outside the function
echo "in shell":
. /tmp/show 

# Display the same values from a subshell
echo "in subshell":
/tmp/show

# Display the same values from a disconnected shell (simulated here by a clean environment start)
echo "in other shell"
env -i /tmp/show 

производит этот вывод:

in function:
[one] [two] [three]
in shell:
[one] [two] []
in subshell:
[one] [] []
in other shell
[] [] []

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

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

27
27.01.2020, 19:35

Лучшее объяснение, которое я могу найти об экспорте, является этим:

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

3
27.01.2020, 19:35
  • 1
    , таким образом, я был неправильным использовать термин "переменная среды" для FOO=bar; необходимо использовать export сделать его один. Вопрос исправлен соответственно. –  Nathan Long 24.12.2011, 14:35
  • 2
    Смотрите на ссылку, которую я включил. –  Karlson 26.12.2011, 21:37

Как и ожидалось, существует иерархия областей видимости переменных.

Окружающая среда

Внешняя область - это окружающая среда. Это единственная область, управляемая операционной системой, и поэтому гарантированно существует для каждого процесса. Когда процесс запускается, он получает копию своей родительской среды, после чего оба становятся независимыми: изменение дочерней среды не изменяет родительскую, а изменение родительской среды не меняет среду уже существующего дочернего.

Переменные оболочки

Оболочки имеют собственное понятие переменных. Здесь все начинает немного запутываться.

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

Здесь в игру вступает ключевое слово export . Он копирует переменную оболочки в среду процесса оболочки, что позволяет дочерним процессам наследовать.

Локальные переменные

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

3
27.01.2020, 19:35

Теги

Похожие вопросы