Bash – Why bash does not spawn a subshell for simple commands

bashshellshell-scriptsubshell

Consider the two following bash commands. One creates a subshell and the other does not.

No subshell

$ bash -c "sleep 10000 "

pstree output:

bash,100648
  └─sleep,103509 10000

With subshell

$ bash -c "sleep 10000; sleep 99999 "


bash,100648
  └─bash,103577 -c sleep 10000; sleep 99999
      └─sleep,103578 10000

Is this some kind of an optimization ? Bash looks at the command and skips the process creation for simple commands. It looks like the simple command is spawned by the parent terminal’s bash.


Bash version I am using is

$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

Though, I think the same can be observed in bash 3.X too.


Some more examples.
With builtins the subshell gets spawned. Builtins are not executed in the parent bash.

$ bash -c "read"

bash,100648
  └─bash,104336 -c read

Same behavior with sleep can be reproduced with top and with output redirect.

$ bash -c "top -b "
bash,100648
  └─top,104392 -b

And

$ bash -c "top -b > /dev/null "
bash,100648
  └─bash,104420 -c top -b > /dev/null
      └─top,104421 -b

Best Answer

The output of pstree is misleading.

bash -c "sleep 10000 "

does create a bash child process. But this process does not create another child process. Because there is nothing more to do after running sleep the shell makes a direct execve() to sleep without forking first.

Because this is so fast you just see the result after the execve in pstree.

But in the

bash -c "sleep 10000; sleep 99999 "

case the new bash forks twice, once for each command. It could make an execve to the last command, too, instead of forking first. I don't know why it does not.

This and the redirection case are probably just problems with the detection when a fork is necessary.

Related Question