4

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 ?

Pengcheng
  • 439
  • 1
  • 4
  • 14

2 Answers2

4

If a command is terminated by the control operator &, the shell executes the command (or list of commands that are enclosed in {...}) in the background (or asynchronously) in a subshell.

The shell does not wait for the command to finish, and the return status is 0.

In C program it is done by doing a fork() followed by execvp() system calls.


Update: Based on comments below and updated question. Here is what is happening.

When you run:

./a.out &

BASH directly just runs a.out in background as running binary a.out doesn't need a separate shell process.

When you run:

{ ./a.out; } &

BASH must first fork and create a subshell as you can have series of commands inside {...} and then the newly forked subshell runs a.out in a separate process. So it is not that BASH is creating 2 subshells for this. Only one subshell gets created and 2nd pid you're seeing is for a.out.

anubhava
  • 761,203
  • 64
  • 569
  • 643
4

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.

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
  • Dave, thanks. But I don't know why commond ”{ ./a.out } &" causes two subshell created? – Pengcheng May 14 '16 at 10:59
  • It doesn't; it only creates one additional shell (PID 1003 in your example) to manage the pipeline. In your example, PID 1002 seems to be a script that contains "{ ./a.out } &", which is its own shell for a different reason. – Dave Schweisguth May 14 '16 at 11:05
  • using shell (PID 1003) to manage the pipeline? Can you explain in detail, please – Pengcheng May 14 '16 at 11:13
  • That's what I explained in my answer: the subshell waits for each command to finish and starts the next. I shouldn't really have said "pipeline", though, since the commands aren't piped one to the next. It's a sequence of separate commands. – Dave Schweisguth May 14 '16 at 11:14
  • Dave, I've figured out. Thanks for your help. – Pengcheng May 14 '16 at 11:30