Considere os seguintes comandos:
exit > /dev/null
exit | cat
Em alguns shells (ksh, bash, (d)ash), o comportamento é o mesmo: o primeiro comando faz com que o shell seja encerrado imediatamente, enquanto o segundo não tem comportamento visível.
Concluí que o primeiro comando não envolvia um fork(2), enquanto o segundo comando envolvia dois (um para executar exit
, o outro execve(2)s para cat
).
Eu olhei para a seção de especificação POSIX 2.14, mas não encontrei nada explicitamente afirmando isso.
É especificado pelo POSIX que alguns comandos não devem ser bifurcados (2) enquanto outros devem? A geração de um subshell para o primeiro comando é aceitável pelo padrão?
Estou ciente de que ( exit )
nunca deve sair do shell atual, porque os parênteses geram um sub-shell que realmente executa o exit
comando, o que significa que o sub-shell sairá imediatamente. No entanto, não tenho certeza sobre redirecionamentos e tubulação, pois não há parênteses aqui.
Estou fazendo esta pergunta porque em um laboratório de curso recente, nos disseram para implementar um shell Unix mínimo. Existem muitos "recursos opcionais" que podemos implementar, para pontos adicionais. Um desses "recursos opcionais" é o redirecionamento e o pipeline combinados. Tivemos algumas implementações diferentes e acredito que algumas estão mais próximas do comportamento especificado do POSIX do que outras e, portanto, gostaria de saber como o comportamento real é especificado.
Bem ( saída ),
e ( 2.12. Ambiente de Execução do Shell )
Portanto, o
exit
em um pipeline é executado em um ambiente/subshell de execução próprio e sai apenas disso, enquanto o do comando simplesexit > /dev/null
é executado no ambiente do shell principal. (Conforme observado nos comentários, o redirecionamento realmente não o afeta.)Observe que a parte no meio da segunda citação significa que algum shell pode executar todos os comandos de um pipeline no ambiente principal, saindo assim do shell inteiro mesmo nesse caso. Na prática, isso é feito mais comumente para o último comando de um pipeline.
No Bash com
lastpipe
, por exemplo:Mas
não imprime nada.
Isso ocorre porque
exit
é executado em um subshell paraexit | cat
e não paraexit > /dev/null
. Sair de um subshell não sai do shell principal :Mas a diferença específica de subshell ou não subshell é especificada na seção 2.12 do padrão POSIX – para citar a passagem relevante na íntegra:
Aqui
exit | cat
cabe a descrição:E, portanto, geralmente será executado em um subshell. No entanto, isso pode pegá-lo:
... Significa que não é garantido em todas as conchas. Anteriormente, tive que depurar código em que uma implementação executava o lado direito de um pipe no shell atual, permitindo que o seguinte funcionasse em algumas implementações de KSH, mas não em outras:
Portanto, sempre assuma que um pipe pode gerar um subshell, mas não confie nele.