Подоболочка начинается с почти идентичной копии исходного процесса оболочки. Под капотом оболочка вызывает fork
системный вызов 1 , который создает новый процесс, чей код и память являются копиями 2 . Когда подоболочка создана, между ней и ее родителем очень мало различий. В частности, они имеют одинаковые переменные. Даже $$
специальная переменная сохраняет то же значение в подоболочках: это идентификатор процесса исходной оболочки. Точно так же $PPID
PID родителя оригинальной оболочки.
Несколько оболочек изменяют несколько переменных в подоболочке. Bash устанавливает BASHPID
PID процесса оболочки, который изменяется в подоболочках. Bash, zsh и mksh обеспечивают $RANDOM
получение разных значений в родительском и подоболочке. Но кроме встроенных особых случаев, подобных этим, все переменные в подоболочке имеют то же значение, что и в исходной оболочке, то же состояние экспорта, то же состояние только для чтения и т. Д. Все определения функций, определения псевдонимов, параметры оболочки и другие настройки также наследуются.
У подоболочки, созданной с помощью (…)
тех же файловых дескрипторов, что и у ее создателя. Некоторые другие средства создания подоболочек изменяют некоторые файловые дескрипторы перед выполнением пользовательского кода; например, левая сторона трубы проходит в подоболочке 3 со стандартным выходом, подключенным к трубе. Подоболочка также начинается с того же текущего каталога, с той же маской сигналов и т. Д. Одним из немногих исключений является то, что подоболочки не наследуют пользовательские прерывания: игнорируемые сигналы ( ) остаются игнорируемыми в подоболочке, но другие прерывания ( SIGNAL ) сбрасываются к действию по умолчанию 4 .trap '' SIGNAL
trap CODE
Таким образом, подоболочка отличается от выполнения скрипта. Сценарий - это отдельная программа. Эта отдельная программа по совпадению может также быть сценарием, который выполняется тем же интерпретатором, что и родительский, но это совпадение не дает отдельной программе особой видимости внутренних данных родителя. Неэкспортированные переменные являются внутренними данными, поэтому , когда интерпретатор сценария ребенка оболочечного выполняются , он не видит эти переменных. Экспортируемые переменные, то есть переменные среды, передаются в исполняемые программы.
Таким образом:
x=1
(echo $x)
печатает, 1
потому что подоболочка является копией оболочки, которая ее породила.
x=1
sh -c 'echo $x'
иногда запускается оболочка как дочерний процесс оболочки, но x
вторая строка не имеет больше связи со x
второй строкой, чем
x=1
perl -le 'print $x'
или же
x=1
python -c 'print x'
1 Исключением является ksh93
оболочка, в которой разветвление оптимизировано, и большинство его побочных эффектов эмулируется.
2 Семантически, это копии. С точки зрения реализации, происходит много обмена.
3 Для правой стороны это зависит от корпуса.
4 Если вы проверите это, обратите внимание, что подобные вещи$(trap)
могут сообщать о ловушках оригинальной оболочки. Также обратите внимание, что во многих снарядах в угловых случаях есть ошибки, связанные с ловушками. Например, ninjalj отмечает, что в bash 4.3 bash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )'
запускается ERR
ловушка из вложенной подоболочки в случае «двух подоболочек», но не ERR
ловушка из промежуточной подоболочки - set -E
опция должна распространятьERR
перехватывать все подоболочки, но промежуточный подоболочек оптимизирован, и поэтому его не удается запустить ERR
.
x=out; (x=in; echo $x)
)