В Learning Bash Book упоминается, что подоболочка будет наследовать только переменные среды, дескрипторы файлов и т. Д. И что она не будет наследовать переменные, которые не экспортируются:
$ 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
должен иметь одинаковое адресное пространство процесса родителя, так почему в ()
случае, если переменная видима для подоболочки, и то же самое не происходит для ./file
случая, хотя те же аргументы основаны на системном вызове clone?
Ответы:
Книга обучения Bash не так. Подоболочки наследуют все переменные. Четный
$$
(PID оригинальной оболочки) сохраняется. Причина в том, что для подоболочки оболочка просто разветвляется и не выполняет новую оболочку (наоборот, при вводе./file
выполняется новая команда, например, новая оболочка; в выводе strace смотритеexecve
и т. П.) , Так что, в основном, это просто копия (с некоторыми документированными отличиями).Примечание: это не относится только к bash; это верно для любой оболочки.
источник
-f
опциюstrace
для отслеживания детей? Это необходимо, чтобы найти исполнителя.Либо вы, либо книга путаете подоболочку с подпроцессом, который является оболочкой.
Некоторые конструкции оболочки приводят к тому, что оболочка разветвляется на дочерний процесс. Под Linux
fork
это особый случай более общегоclone
системного вызова, который вы наблюдали вstrace
журнале. Ребенок запускает часть сценария оболочки. Дочерний процесс называется подоболочкой . Наиболее прямая такая конструкцияcommand1 &
:command1
выполняется в подоболочке, а последующие команды выполняются в родительской оболочке. Другие конструкции, которые создают подоболочку, включают подстановку команд$(command2)
и каналыcommand3 | command4
(command3
выполняется в подоболочке,command4
в большинстве оболочек выполняется в подоболочке, но не в ksh или zsh).Подоболочка - это копия родительского процесса, поэтому она имеет не только те же переменные среды, но и все те же внутренние определения: переменные (включая
$$
идентификатор процесса исходного процесса оболочки), функции, псевдонимы, параметры и т. Д. Перед выполнением кода в подоболочке bash устанавливает переменнуюBASHPID
в идентификатор процесса дочернего процесса.Когда вы запускаете
./file
, это выполняет внешнюю команду. Во-первых, оболочка разветвляет дочерний процесс; затем этот дочерний процесс выполняет (с помощьюexecve
системного вызова) исполняемый файл./file
. Дочерний процесс наследует атрибуты процесса своих родителей: окружение, текущий каталог и т. Д. Внутренние аспекты приложения теряются приexecve
вызове: неэкспортированные переменные, функции и т. Д. Являются понятиями bash, о которых ядро не знает, и они теряются, когда bash выполняет другую программу. Даже если эта другая программа оказывается сценарием bash, она выполняется новым экземпляром bash, который не знает или не заботится о том, что его родительский процесс также является экземпляром bash. Таким образом, переменная оболочки (неэкспортированная переменная) не сохраняетсяexecve
.источник