Um subshell duplica o shell existente. Tem as mesmas variáveis¹, as mesmas funções, as mesmas opções, etc. Sob o capô, um subshell é criado com o fork
chamada do sistema²; o processo filho continua a fazer o que se espera dele enquanto o pai espera (por exemplo, $(…)
) ou continua sua vida (por exemplo, … &
) ou faz o que é esperado dele (por exemplo, … | …
).
sh -c …
não cria um subshell. Ele lança outro programa. Esse programa é uma concha, mas isso é apenas uma coincidência. O programa pode até ser um shell diferente (por exemplo, se você executar sh -c …
do bash e sh
for traço), ou seja, um programa completamente diferente que por acaso tenha semelhanças significativas em seu comportamento. Sob o capô, lançar um comando externo ( sh
ou qualquer outro) chama a chamada de sistema fork
e, em seguida, a execve
chamada do sistema para substituir o programa shell no subprocesso por outro programa (aqui sh
).
¹ Incluindo $$
, mas excluindo algumas variáveis específicas do shell, como bash e mksh BASHPID
.
² Pelo menos, essa é a implementação tradicional e usual. Os reservatórios podem otimizar o garfo, caso contrário, podem imitar o comportamento.
Páginas de manual relevantes: fork (2) , execve (2) .