Почему переменная видима в подоболочке?

В книге Learning Bash упоминается, что подоболочка наследует только переменные среды и файловые дескрипторы и т. Д. И что она не будет наследовать переменные, которые не экспортируются:

$ var=15 $ (echo $var) 15 $ ./file # this file include the same command echo $var $ 

Как я знаю, оболочка создаст две подоболочки для () и для ./file , но почему в случае () подселлер идентифицирует переменную var хотя она не экспортируется, а в случае ./file она не идентифицировала ее?

 # Strace for () clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617 # Strace for ./file clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631 

Я попытался использовать strace чтобы выяснить, как это происходит, и я неожиданно обнаружил, что bash будет использовать те же аргументы для системного вызова clone, поэтому это означает, что и разветвленный процесс в () и ./file должен иметь одно и то же адресное пространство процесса родительского, так почему в case () есть переменная, видимая для подоболочки, и то же самое не происходит для случая ./file , хотя те же аргументы основаны на системном вызове клона?

2 Solutions collect form web for “Почему переменная видима в подоболочке?”

Книга Изучения Баша ошибочна. Подголовки наследуют все переменные. Даже $$ (PID исходной оболочки) сохраняется. Причина в том, что для подоболочки оболочка просто вилки и не выполняет новую оболочку (напротив, при ./file выполняется новая команда, например, новая оболочка; в выводе strace смотрите execve и тому подобное). Итак, в основном, это всего лишь копия (с некоторыми документальными различиями).

Примечание: это не относится к bash; это верно для любой оболочки.

Либо вы, либо книга путаете подоболочку с подпроцессом, который является оболочкой.

Некоторые конструкции оболочки приводят к тому, что оболочка разбивает дочерний процесс. В Linux fork – это особый случай более общего системного вызова clone , который вы наблюдали в журнале strace . Ребенок выполняет часть сценария оболочки. Детский процесс называется подоболочкой . Самой прямой такой конструкцией является command1 & : command1 работает в подоболочке, а последующие команды выполняются в родительской оболочке. Другие конструкции, которые создают подоболочку, включают подстановку команд $(command2) и pipe command3 | command4 command3 | command4 ( command3 запускается в подоболочке, command4 запускается в подоболочке в большинстве оболочек, но не в ksh или zsh).

Подселлем является копия родительского процесса, поэтому он имеет не только одни и те же переменные среды, но и все те же внутренние определения: переменные (включая $$ , идентификатор процесса исходного процесса оболочки), функции, псевдонимы, параметры, и т. д. Перед выполнением кода в подоболочке bash устанавливает переменную BASHPID в идентификатор процесса дочернего процесса.

Когда вы запускаете ./file , это выполняет внешнюю команду. Во-первых, оболочка виляет дочерний процесс; то этот дочерний процесс выполняет (с системным вызовом execve ) исполняемый файл ./file . Детский процесс наследует атрибуты процесса своих родителей: среда, текущий каталог и т. Д. Внутренние аспекты приложения теряются в вызове execve : неэкспортируемые переменные, функции и т. Д. – это понятия bash, о которых ядро ​​не знает, и они теряются, когда bash выполняет другую программу. Даже если эта другая программа является сценарием bash, она выполняется новым экземпляром bash, который не знает или не заботится о том, чтобы его родительский процесс также являлся экземпляром bash. Таким образом, переменная оболочки (неэкспортированная переменная) не выдерживает execve .

Linux и Unix - лучшая ОС в мире.