Вчера мне подсказали, что использование подстановки команд в bash приводит к созданию ненужной подоболочки. Совет относился к этому варианту использования:
# Extra subshell spawned
foo=$(command; echo $?)
# No extra subshell
command
foo=$?
Насколько я могу судить, это кажется правильным для этого варианта использования. Однако быстрый поиск, пытающийся проверить это, приводит к множеству запутанных и противоречивых советов. Кажется, народная мудрость гласит, что ВСЕ использование подстановки команд порождает подоболочку. Например:
Подстановка команд расширяется до вывода команд. Эти команды выполняются в подоболочке, и их данные stdout — это то, до чего расширяется синтаксис подстановки. (источник)
Это кажется достаточно простым, если вы не продолжите копать, и в этом случае вы начнете находить ссылки на предположения, что это не так.
Подстановка команд не обязательно вызывает подоболочку и в большинстве случаев не вызывает. Единственное, что он гарантирует, — это вычисление не по порядку: он просто сначала вычисляет выражения внутри подстановки, а затем оценивает окружающий оператор, используя результаты подстановки. (источник)
Это кажется разумным, но так ли это? Этот ответ на вопрос, связанный с подоболочкой, подсказал мне, что man bash
имеет следующее замечание:
Каждая команда в конвейере выполняется как отдельный процесс (т. е. в подоболочке).
Это подводит меня к главному вопросу. Что именно приведет к тому, что подстановка команд порождает подоболочку, которая в любом случае не была бы создана для выполнения тех же команд по отдельности?
Пожалуйста, рассмотрите следующие случаи и объясните, какие из них несут накладные расходы на дополнительную подоболочку:
# Case #1
command1
var=$(command1)
# Case #2
command1 | command2
var=$(command1 | command2)
# Case #3
command1 | command 2 ; var=$?
var=$(command1 | command2 ; echo $?)
Выполняется ли для каждой из этих пар одинаковое количество подоболочек? Есть ли разница в реализациях POSIX и bash? Есть ли другие случаи, когда использование подстановки команд порождает подоболочку, тогда как выполнение одного и того же набора команд по отдельности не приводит к возникновению?
bash
. Однако я бы отметил, что подоболочка != process; подоболочка (в смысле новой области действия для переменных) не требуется для порождения нового процесса для его запуска. (Это третий пункт в принятом ответе на ваш связанный вопрос.) - person chepner   schedule 24.01.2014( ... )
явно создает подоболочку; команды в круглых скобках должны выполняться в дополнительной оболочке (это означает, что любые изменения, внесенные в переменные и т. д., не должны влиять на основную оболочку). Раньше это делалось путем разветвления и предоставления дочернему элементу выполнения содержимого сценария вложенной оболочки, в то время как родитель ожидает его завершения. Оболочка может избежать этого, если у нее достаточно хорошие возможности определения области видимости. - person Jonathan Leffler   schedule 24.01.2014