Bash subshell/pipelines - which parts are executing in subshells?
Indeed, the braces are executed in a new subshell, but only if piped. The first command is with cat
, the second without:
xxx@yyy:~$ 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
xxx@yyy:~$ 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
In this case 6768
is the PID of the terminal shell, and 13159
is the PID of the subshell started for the braces.
It seems that {}
are executed in a subshell if (and only if) piped.
Each side of a pipeline becomes a subshell at least.
X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
will make a subshell/process of , atleast { X=ABC; echo $X; }
and cat
.
"Each command in a pipeline is executed as a separate process (i.e., in a subshell)." , from man bash
If you instead do this
X=PQR; echo $X; { X=ABC; echo $X; } ; echo | cat; echo $X
You'll see afterwards that echo $X
shows ABC.
There's other ways that commands are executed in subshells too, e.g. if you background a subcommand: { X=SUB ; sleep 1; } &
, that group will run in a subshell, whereas just { X=SUB ; sleep 1; }
will not.
If you want to group commands that always execute in a subshell, use parenthesis, (X=ABC ; echo $X)
instead of braces.