Pengcheng Pengcheng - 6 months ago 16
Bash Question

Why does shell command “{ command1; command2: } &" open a subshell?

As we all know, placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. But when using "&" after "{}", why two subshells are created? pid 1002 and 1003.

{
./a.out
} &

sleep 19


enter image description here

when using "./a.out &", only a subshell is created. pid 17358.

./a.out &
sleep 19


enter image description here

Why ?

Answer

Background execution of a list uses a subshell because something needs to wait for each member of that list and run the next one. After a list is backgrounded, the parent shell needs to be available for new commands; it can't manage the backgrounded list too. bash can't do more than one thing at a time. So, to make the backgrounded list work, it runs a subshell.

Note that you can disown a backgrounded list and it will keep running, showing that the subshell is doing its work:

$ {
> sleep 1; sleep 2; sleep 3; sleep 4; sleep 5
> } &
$ disown
$ ps -f | grep sleep
dave     31845 31842  0 03:50 pts/1    00:00:00 sleep 3 
dave     31849 31771  0 03:50 pts/1    00:00:00 grep sleep

You could even log out and the subshell would continue running processes in the list.

When you background a single command, there is no need for a subshell because there is no more work for the shell to do after it has run the command.

In your example, the second additional bash subprocess, PID 1002, appears to be a script which you're executing. That's unrelated (conceptually, at least) to the list-backgrounding mechanism; any script in a separate file has its own bash process.