somefile
contém isto:
aaa
bbb
ccc
Este é o subshell que pode sair antes de concluir todas as iterações. No meu caso particular é, while
mas poderia ser for
ou until
:
cat "somefile" | while read -r line
do
echo "$line"
if [ "$line" = "bbb" ]
then
exit 2
fi
done
exit_code="$?"
if [ "$exit_code" -ne 0 ]
then
exit
fi
echo "I'm here"
O problema é que a última linha I'm here
é impressa. Minha intenção é sair completamente para o terminal. No entanto, não tenho certeza se isso está correto e funcionará com todos os shells. Isso é mesmo POSIX? Alguma menção sobre como isso deve funcionar no POSIX?
Perguntei a vários mecanismos de IA e cada um deles vem com uma resposta diferente:
- Copiloto: diz que o exit_code será sempre 0, pois esse é o código de saída do cat. Poderia ser qualquer outro comando.
- ChatGPT: diz que o exit_code será o número após a saída, como aqui 2, porque se propaga.
- Gêmeos: diz que o exit_code será sempre 0, porque $? obtém o código de saída da última instrução, que é
done
e é sempre 0.
Alguma ajuda aqui? Eu tentei no bash e ele detecta o código de saída, mas não tenho certeza se é alguma configuração específica do bash (como pipefail ou é a maneira como funciona com qualquer shell (por exemplo, no UNIX também).
O status de saída de um pipeline é o do componente mais à direita se a
pipefail
opção¹ estiver desativada (padrão) ou o do componente mais à direita que tiver um status de saída diferente de zero sepipefail
estiver ativado.Por exemplo, o status de saída
(exit 12) | (exit 5) | (exit 0)
será 0 sempipefail
e 5 com.Agora, em um
sh
pipeline, o POSIX não especifica se o último componente (mais à direita) de um pipeline é executado em um subshell ou não e, na prática, isso varia comsh
a implementação.Portanto, dependendo do shell, isso
exit 2
, se executado, sairá completamente do script ou sairá apenas do subshell que executa essewhile
loop. Neste último caso, o status de saída do pipeline será 2, independentemente de apipefail
opção estar ativada ou não.Aqui, embora você fizesse algo como:
Isso é invocar um utilitário de processamento de texto para fazer o processamento de texto, não centenas de invocações (assumindo a entrada de centenas de linhas) de ferramentas inadequadas, como
read
,echo
,[
.Veja também:
¹ uma extensão ksh agora encontrada na maioria
sh
das implementações e especificada pelo POSIX desde a edição 2024 do padrão, mas ainda não encontrada em todas as implementações e, em particular, nãodash
.De acordo com POSIX :
O último comando é o
while
loop. O status de saída de umwhile
loop é sempre 0, a menos que o shell que o executa saia sem concluir o loop.Todas as conchas semelhantes a sh se comportam assim. 1
Parte do comportamento depende do shell, entretanto. A maioria dos shells do tipo sh, incluindo o clássico Bourne shell, bash, dash e mksh, correm cada lado do tubo em um subshell. Se
exit 2
for alcançado, ele sai do subshell para o lado direito do tubo, então a linhaexit_code="$?"
é definidaexit_code
como 2. No ATT ksh e zsh, o lado direito de um tubo é executado no shell principal, portanto, seexit 2
for alcançado , todo o script sai com o status 2 e a linhaexit_code="$?"
nunca é executada.A única maneira
echo "I'm here"
de chegar é se o arquivo não contiver uma linha que contenha exatamentebbb
.Se você estiver trabalhando no Windows, certifique-se de que seu arquivo tenha terminações de linha Unix, e não terminações de linha do Windows. Os finais de linha do Windows consistem em dois caracteres CR LF, enquanto os finais de linha do Unix são apenas LF, portanto, as ferramentas Unix veem as linhas do Windows como contendo o texto esperado mais um caractere CR.
1 Para completar: alguns shells podem ser configurados para dar ao pipe um status diferente de zero se algum dos comandos falhar ao executar
set -o pipefail
. Com esta configuração, se owhile
loop retornar 0, você obterá o status de saídacat
, que será 0 se o arquivo fornecido puder ser lido.