В терминологии POSIX среда подоболочки связана с понятием среды выполнения Shell .
Среда subshell - это отдельная среда выполнения оболочки, созданная как дубликат родительской среды. Эта среда выполнения включает в себя такие вещи, как открытые файлы, umask, рабочий каталог, переменные оболочки / functions / aliases ...
Изменения в этой среде оболочки не влияют на родительскую среду.
Традиционно в оболочке Bourne или ksh88, на которой основана спецификация POSIX, это было сделано путем разветвления дочернего процесса.
Области, где POSIX требует или разрешает запуск команды в среде подоболочек, - это области, где традиционно ksh88 разветвлял дочерний процесс оболочки.
Однако это не заставляет реализации использовать дочерний процесс для этого.
Вместо этого оболочка может реализовать эту отдельную среду выполнения любым удобным для них способом.
Например, ksh93 делает это, сохраняя атрибуты родительской среды выполнения и восстанавливая их после завершения среды subshell в тех случаях, когда можно избежать разветвления (поскольку оптимизация, поскольку разветвление довольно дорого в большинстве систем).
Например, в:
cd /foo; pwd
(cd /bar; pwd)
pwd
POSIX требует, cd /foo
чтобы он работал в отдельной среде и выводил что-то вроде:
/foo
/bar
/foo
Он не требует запуска в отдельном процессе. Например, если stdout становится прерванным каналом, pwd
запуск в среде subshell вполне может иметь отправку SIGPIPE в один-единственный процесс оболочки.
Большинство оболочек, в том числе bash
, реализуют его, оценивая код внутри (...)
дочернего процесса (пока родительский процесс ожидает его завершения), но вместо этого ksh93 выполнит код внутри (...)
, все в одном процессе:
- помните, что это в недолговечной среде.
- после
cd
, сохранить предыдущий рабочий каталог ( как правило дескриптор файла , открытый O_CLOEXEC), за исключением стоимости OLDPWD, PWD переменных и все , что cd
может изменить , а затем сделатьchdir("/bar")
- по возвращении из subshell текущий рабочий каталог восстанавливается (с
fchdir()
сохраненным fd) и всем остальным, что subshell мог изменить.
Существуют контексты, в которых нельзя избежать дочернего процесса. ksh93 не разветвляется:
var=$(subshell)
(subshell)
Но делает в
{ subshell; } &
{ subshell; } | other command
То есть случаи, когда вещи должны запускаться в отдельных процессах, чтобы они могли работать одновременно.
Оптимизация ksh93 идет дальше этого. Например, в то время как в
var=$(pwd)
большинство оболочек будет обрабатывать процесс, дочерний процесс запускает pwd
команду с перенаправленным stdout в канал, pwd
записывает текущий рабочий каталог в этот канал, а родительский процесс считывает результат на другом конце канала, ksh93
виртуализирует все это ни одним из них. требуя вилки или трубы. Вилка и труба будут использоваться только для не встроенных команд.
Обратите внимание, что существуют контексты, отличающиеся от подоболочек, для которых оболочки разветвляют дочерний процесс. Например, чтобы запустить команду, которая хранится в отдельном исполняемом файле (и это не сценарий, предназначенный для того же интерпретатора оболочки), оболочка должна была бы разветвить процесс, чтобы запустить в нем эту команду, иначе это было бы не так. возможность выполнить больше команд после того, как эта команда вернется.
В:
/bin/echo "$((n += 1))"
Это не подоболочка, команда будет оцениваться в текущей среде выполнения оболочки, n
переменная текущей среды выполнения оболочки будет увеличиваться, но оболочка будет разветвлять дочерний процесс для выполнения этой /bin/echo
команды с расширением $((n += 1))
аргумента as. ,
Многие оболочки реализуют оптимизацию в том смысле, что они не разветвляют дочерний процесс для запуска этой внешней команды, если это последняя команда скрипта или подоболочки (для тех подоболочек, которые реализованы как дочерние процессы). ( bash
однако это происходит только в том случае, если эта команда является единственной командой подоболочки).
Это означает, что с этими оболочками, если последняя команда в подоболочке является внешней командой, подоболочка не приводит к созданию дополнительного процесса. Если вы сравните:
a=1; /bin/echo "$a"; a=2; /bin/echo "$a"
с
a=1; /bin/echo "$a"; (a=2; /bin/echo "$a")
будет создано такое же количество процессов, только во втором случае второй ветвь выполняется раньше, так что a=2
он запускается в среде подоболочек.