Какова точная разница между «подоболочкой» и «дочерним процессом»?

16

Согласно этому и этому , подоболочка запускается с использованием круглых скобок (…).

( echo "Hello" )

В соответствии с этим , этим и этим процесс разветвляется, когда команда запускается с&

echo "Hello" &

Спецификация Posix использует слово subshellна этой странице, но не определяет его, а также на той же странице не определяет «дочерний процесс» .

Оба используют fork()функцию ядра , правильно?

Какая разница в том, чтобы называть некоторые вилки «вложенной оболочкой», а некоторые другие - «дочерними процессами».

NotAnUnixNazi
источник
Непонятно, почему вы связываете POSIX Обоснование: базовые определения вместо самих базовых определений : 3.93 Дочерний процесс «Новый процесс, созданный (с помощью fork (), posix_spawn () или ...) данным процессом» ; 3.376 Subshell «Среда выполнения оболочки, отличная от основной или текущей среды выполнения оболочки» . Таким образом, не случаи одного и того же рода вещи. Это различие, которое вы ищете?
Фра-Сан
@ Fra-San A child processможет иметь отличную среду, чем main: Как в ( LANG=C eval 'echo "$LANG"' ). Является ли этот дочерний процесс (внутри круглых скобок) также подоболочкой (в другой среде)?
NotAnUnixNazi
Выражение ( )это по определению Подоболочка со своей собственной средой исполнения. Я хочу сказать, что подоболочка не должна быть реализована как дочерний процесс (как указывает Стефан в своем ответе на примере ksh93). Похоже, подоболочка и дочерний процесс не должны быть оба результата fork()вызова; таким образом, поиск различий между двумя типами вилок не кажется мне правильной точкой зрения. Вот почему я пытался лучше понять ваш вопрос.
Фра-Сан
Ах, теперь я вижу, что на странице tldp , на которую вы ссылаетесь , фактически говорится, что подоболочка - это дочерний процесс. На мой взгляд, это определение, возможно, вводящее в заблуждение упрощение.
фра-сан

Ответы:

15

В терминологии 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он запускается в среде подоболочек.

Стефан Шазелас
источник
1

подоболочка

Дочерняя оболочка также называется subshell. Subshell может быть создан из родительской оболочки и из другой оболочки. Subshell может быть создан с помощью:

1. Список процессов

Список процессов - это группировка команд, заключенная в круглые скобки. Пример:

( pwd ; (echo $BASH_SUBSHELL)) 

Это напечатает текущий рабочий каталог и номер порожденной оболочки. ПРИМЕЧАНИЕ. Вызвать подоболочку дорого.

2. Копроцесс

Он порождает подоболочку в фоновом режиме и выполняет команду внутри этой подоболочки.

coproc sleep 10

Если вы введете jobsкоманду

[1]+  Running                 coproc COPROC sleep 10 &

вы увидите сон как фоновый процесс, работающий в фоновом режиме.

Форкинг дочернего процесса

Дочерний процесс в вычислениях - это процесс, созданный другим процессом. Всякий раз, когда выполняется внешняя команда, создается дочерний процесс. Это действие называется разветвлением.

$ps -f
UID        PID  PPID  C STIME TTY          TIME CMD  
umcr7     3647  3638  0 13:54 pts/0    00:00:00 bash
umcr7     3749  3647  0 13:59 pts/0    00:00:00 ps -f

Как ps -fи внешняя команда (т. Е. Внешняя команда, иногда называемая командой файловой системы, представляет собой программу, которая существует вне оболочки bash.) Она создаст дочерний процесс с родительским идентификатором оболочки bash, из которой она выполняется.

Мухаммед Умар Аманат
источник
0

Оба (subshell и дочерняя оболочка) являются отдельным процессом, нежели родительская оболочка (оба являются дочерними элементами родительской оболочки). То есть у них разные PID. И оба начинаются с форка (копии) родительской оболочки.

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

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

Подоболочка может получить доступ к значениям переменных:

$ x=123; ( echo "$x")
123

Дочерняя оболочка не может (не экспортируемые переменные):

$ x=234; sh -c 'echo "x=$x"'
x=
NotAnUnixNazi
источник