Подтвердить что ты не робот

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

Как и ожидалось, оболочка порождает две подоболочки, по одной на каждую сторону трубопровода.

4b9b3361

Ответ 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 (и только если).