Parece que eu entendi mal a regra do Bash para criar um subshell. Eu pensei que parênteses sempre cria um subshell, que roda como seu próprio processo.
No entanto, este não parece ser o caso. No Snippet de código A (abaixo), o segundo sleep
comando não é executado em um shell separado (conforme determinado por pstree
outro terminal). No entanto, no Snippet de código B, o segundo sleep
comando é executado em um shell separado. A única diferença entre os trechos é que o segundo trecho possui dois comandos entre parênteses.
Alguém poderia, por favor, explicar a regra para quando subcascas são criadas?
SNIPPET A DO CÓDIGO:
sleep 5
(
sleep 5
)
SNIPPET B DO CÓDIGO:
sleep 5
(
x=1
sleep 5
)
fonte
fork
e o processo filho é criado (para executar comandos externos) chamandofork + exec
. Mas o seu primeiro parágrafo sugere que tambémfork + exec
é necessário um subshell. O que estou errado aqui?fork
+exec
não é chamado para o subshell, é chamado para o comando externo. Sem qualquer otimização, há umafork
chamada para o subshell e outra para o comando externo. Adicionei uma descrição detalhada do fluxo à minha resposta.(...)
(no caso base), pode ou não haver uma chamada paraexec
depende se o subshell tem algum comando externo para executar, enquanto no caso de executar qualquer comando externo deve haverfork + exec
.date
em um shell?strace -f -e clone,execve,write bash -c 'date'
estrace -f -e clone,execve,write bash -c 'date; true'
No Guia de programação avançada do Bash :
"Em geral, um comando externo em um script cria um subprocesso, enquanto um Bash embutido não. Por esse motivo, os embutidos são executados mais rapidamente e usam menos recursos do sistema que seus equivalentes de comando externos."
E um pouco mais abaixo:
"Uma lista de comandos incorporada entre parênteses é executada como um subshell."
Exemplos:
Exemplo usando o código de OPs (com sono mais curto porque estou impaciente):
A saída:
fonte
sleep
executado em um subshell (talvez no processo do subshell, pois é um built-in, em vez de um subprocesso). No entanto, em qualquer caso, eu esperava que existisse um subshell, ou seja, um subprocesso Bash no processo Bash pai. Para o Snippet B acima, este não parece ser o caso.sleep
não parece ser interno, eu esperaria que a segundasleep
chamada nos dois trechos fosse executada em um subprocesso do processo de subshell.$BASHPID
variável. Infelizmente, o jeito que você estava fazendo não estava lhe contando a história toda. Veja minha saída adicionada na resposta.Uma observação adicional à resposta do @Gilles.
Como disse Gilles:
The parentheses always start a subshell.
No entanto, os números que esse sub-shell pode repetir:
Como você pode ver, o $$ continua repetindo, e é o esperado, porque (execute este comando para encontrar a
man bash
linha correta ):Ou seja: Se o shell não for reinicializado, o $$ será o mesmo.
Ou com isso:
O
$$
é o ID do shell atual (não o subshell).fonte