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 chamaforkewait. No subprocesso, que é um subnível:-
sleepé um comando externo que requer um subprocesso do subprocesso. A subshell chamaforkewait. No sub-processo:- O sub-processo executa o comando externo →
exec. - Eventualmente, o comando termina →
exit.
- O sub-processo executa o comando externo →
-
waitconclui no subnível.
-
-
waité concluído no processo original.
A otimização é:
-
( … )cria um subnível. O processo original chamaforkewait. 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).