Os parênteses sempre iniciam um subshell. O que está acontecendo é que o bash detecta que sleep 5
é o último comando executado por esse subshell, então chama exec
em vez de fork
+ exec
. O comando sleep
substitui o subshell no mesmo processo.
Em outras palavras, o caso base é:
-
( … )
cria um subnível. O processo original chamafork
ewait
. No subprocesso, que é um subnível:-
sleep
é um comando externo que requer um subprocesso do subprocesso. A subshell chamafork
ewait
. No sub-processo:- O sub-processo executa o comando externo →
exec
. - Eventualmente, o comando termina →
exit
.
- O sub-processo executa o comando externo →
-
wait
conclui no subnível.
-
-
wait
é concluído no processo original.
A otimização é:
-
( … )
cria um subnível. O processo original chamafork
ewait
. No subprocesso, que é um subshell até chamarexec
:-
sleep
é um comando externo e é a última coisa que esse processo precisa fazer. - O subprocesso executa o comando externo →
exec
. - Eventualmente, o comando termina →
exit
.
-
-
wait
é concluído no processo original.
Quando você adiciona algo após a chamada sleep
, a subshell precisa ser mantida, portanto, essa otimização não pode acontecer.
Quando você adiciona algo antes da chamada para sleep
, a otimização pode ser feita (e o ksh faz isso), mas o bash não faz isso (é muito conservador com essa otimização).