5

After running the command

{ sleep 5; } &  

output of ps is (output 1)

 PID TTY           TIME CMD
  972 ttys000    0:00.27 -bash
 2556 ttys000    0:00.00 -bash
 2557 ttys000    0:00.00 sleep 5   

while for

( sleep 5 ) &    

out of ps is (output 2)

PID TTY           TIME CMD
 972 ttys000    0:00.28 -bash
2566 ttys000    0:00.00 sleep 5  

() causes a subshell environment and I expect "output 1" for this case as it results in forking a child process while I expects "output 2" for { sleep 5; } & as it executes in the current shell. This might look a silly question but I really do not understand this behavior.
What I am missing here?

2
  • It seams a duplicate question. Please check out this link. Maybe it helps. unix.stackexchange.com/a/138498/273268 Commented Mar 13, 2018 at 20:31
  • @YurijGoncharuk; I already read that answer. That addresses related, but different issue.
    – haccks
    Commented Mar 13, 2018 at 20:33

1 Answer 1

11

Bash will run the last or only command of a subshell with exec if it figures it can do so safely, as an optimisation. You can validate this clearly with pstree:

$ pstree $$
bash---pstree
$ ( pstree $$ )
bash---pstree
$ ( pstree $$ ; echo)
bash---bash---pstree

$ 

That is why your ( sleep 5 ) shows up as just the sleep command, and no intermediate shell. In the last example above, the echo forces the shell to do something after pstree completes, so there's a real shell around to use; in the middle case, the spawned shell just immediately execs pstree, so it looks the same as the first case (which is standard fork-exec). Many shells do this.


On the other hand, anything run in the background requires spawning a new process: fundamentally, that's what "background" is. Commands in braces do ordinarily run in the current shell, but that can't happen if they're to run in the background. So that the parent shell can keep doing whatever it's doing while the background commands run, a new shell has to be created to run the whole { ... } in. Thus

$ { pstree $$ ; }
bash---pstree
$ { pstree $$ ; } &
bash---bash---pstree

In this case, there's no difference whether there's another trailing command or not. Bash documents this behaviour for &:

If a command is terminated by the control operator ‘&’, the shell executes the command asynchronously in a subshell. This is known as executing the command in the background. The shell does not wait for the command to finish, and the return status is 0 (true).

You can also see this happen by backgrounding a built-in command like read:

$ read &
$ pstree $$
[1] 32394
[1]+  Stopped                 read
$ pstree $$
bash-+-bash
     `-pstree

My shell now has two children: a bash running read, and the pstree command printing that output.


It's true that the shell could make a further optimisation and apply it to backgrounded { ... } as it does to parenthesised subshells, but it doesn't. It's possible some other shells do, but I haven't found one in quick testing. It's a pretty rare case and formally different, and there are some odd corner cases.

13
  • Generally, the most optimised shell when it comes to saving processes would be ksh93 and the least optimised bash with other shells sitting somewhere it between. Commented Mar 13, 2018 at 21:08
  • anything run in the background requires spawning a new process: so does (sleep 2) &. But it looks same as the case (sleep 2). Even (sleep 2, echo) &1 looks same as (sleep 2) .
    – haccks
    Commented Mar 13, 2018 at 21:17
  • Yes, the only difference between those is whether the parent waits for the child to finish or not. Commented Mar 13, 2018 at 21:20
  • @MichaelHomer; In both cases, (sleep 2) & and { sleep 2; } &, parent doesn't wait for the child to finish as per the behavior of &.
    – haccks
    Commented Mar 13, 2018 at 21:23
  • 1
    (sleep 2) was already a separate process, with one optimised away (first half of the answer), and the only difference the & makes is not waiting for it to finish; { sleep 2; } & becomes a Bash process, which then spawns sleep 2 (second half of the answer). They are not the same. Commented Mar 14, 2018 at 3:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .