Bash subshell/pipelines - какие части выполняются в подоболочках?
В комментарии к другому сообщению @JonathanLeffler заявил, что:
{...} | somecommand запускается в под-оболочке и не влияет на родительскую оболочку. Демо-версия:
X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
(с выводом PQR, ABC, PQR на три строки)
и действительно:
[email protected]:tmp$X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
PQR
ABC
PQR
Однако man bash
говорит, что {.. }
не выполняется в подоболочке:
{ list; }
list is simply executed in the current shell environment. list must be
terminated with a newline or semicolon. This is known as a group command.
Так что здесь происходит? Неужели man bash
не прав? Я знаю, что каждая часть конвейера выполняется в подоболочке; но я не вижу, как это вызывает наблюдаемое поведение. Например:
[email protected]:tmp$X=PQR; echo $X | sed; X=ABC; echo $X | sed; echo $X
PQR
ABC
ABC
Отредактировано, чтобы добавить:
Несколько человек предложили использовать echo $$
чтобы показать, что вещи являются (или не являются) частями подоболочки. Это совсем не полезно, так как $$
раскрывается на этапе расширения параметров, который происходит задолго до того, как будут выполнены какие-либо команды.
В качестве примера:
[email protected]:tmp$echo 1$$; ps; ( echo 2$$; ps ); echo 3$$; ps
11194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
21194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
7894 ttys000 0:00.00 -bash
31194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
[email protected]:tmp$
Вы можете видеть, что второй вызов ps
произошел внутри подоболочки с pid 7894
; но echo 2$$
прежнему показывает значение, которое bash подставил на этапе расширения переменной, до того, как он породил подоболочку
Для контраста и демонстрации того, что {.. }
не порождает подоболочку:
[email protected]:tmp$echo 1$$; ps; { echo 2$$; ps; }; echo 3$$; ps
11194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
21194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
31194
PID TTY TIME CMD
1194 ttys000 0:00.23 -bash
Просто чтобы доказать, что @nos верен, добавьте конвейер к приведенному выше:
[email protected]ious-wired:tmp$echo 1$$; ps; { echo 2$$; ps; } | sed ; echo 3$$; ps
11194
PID TTY TIME CMD
1194 ttys000 0:00.25 -bash
21194
PID TTY TIME CMD
1194 ttys000 0:00.25 -bash
7945 ttys000 0:00.00 -bash
7946 ttys000 0:00.00 sed
31194
PID TTY TIME CMD
1194 ttys000 0:00.25 -bash
Как и ожидалось, оболочка порождает две подоболочки, по одной на каждую сторону трубопровода.
Ответы
Ответ 1
Каждая сторона конвейера становится как минимум подоболочкой.
X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
сделаем подоболочку/процесс, по крайней мере { X=ABC; echo $X; }
{ X=ABC; echo $X; }
{ X=ABC; echo $X; }
и cat
.
"Каждая команда в конвейере выполняется как отдельный процесс (т.е. В подоболочке)". от человека Баш
Если вы вместо этого сделаете это
X=PQR; echo $X; { X=ABC; echo $X; } ; echo | cat; echo $X
После этого вы увидите, что echo $X
показывает ABC.
Существуют и другие способы выполнения команд в подоболочках, например, если вы выполняете фоновую подкоманду: { X=SUB; sleep 1; } &
{ X=SUB; sleep 1; } &
{ X=SUB; sleep 1; } &
, эта группа будет работать в подоболочке, тогда как просто { X=SUB; sleep 1; }
{ X=SUB; sleep 1; }
{ X=SUB; sleep 1; }
не будет.
Если вы хотите сгруппировать команды, которые всегда выполняются в подоболочке, используйте скобки (X=ABC; echo $X)
вместо фигурных скобок.
Ответ 2
Действительно, фигурные скобки выполняются в новой подоболочке , но только в том случае, если они связаны с каналами. Первая команда с cat
, вторая без:
[email protected]:~$ ps; X=PQR; echo $X; { ps; X=ABC; echo $X; } | cat; ps; echo $X
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13158 pts/7 00:00:00 ps
PQR
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13159 pts/7 00:00:00 bash
13160 pts/7 00:00:00 cat
13161 pts/7 00:00:00 ps
ABC
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13162 pts/7 00:00:00 ps
PQR
[email protected]:~$ ps; X=PQR; echo $X; { ps; X=ABC; echo $X; }; ps; echo $X
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13239 pts/7 00:00:00 ps
PQR
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13240 pts/7 00:00:00 ps
ABC
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13245 pts/7 00:00:00 ps
ABC
В этом случае 6768
является PID оболочки терминала, а 13159
является идентификатором PID для подоболочки, начатой для фигурных скобок.
Кажется, что {}
выполняется в подоболочке if (и только если).