Estou tentando entender como o status de saída é comunicado quando um pipe é usado. Suponha que eu esteja usando which
para localizar um programa inexistente:
which lss
echo $?
1
Como which
não foi possível localizar lss
, obtive um status de saída 1. Isso é bom. No entanto, quando tento o seguinte:
which lss | echo $?
0
Isso indica que o último comando executado saiu normalmente. A única maneira de entender isso é que talvez o PIPE também produza um status de saída. Esta é a maneira correta de entender?
bash
shell-script
pipe
exit
sshekhar1980
fonte
fonte
which lss | echo $?
, oecho
é iniciado antes dewhich
sair; o shell que está gerando a linha de comandoecho
não tem como saber qual será o status de saídawhich
posteriormente.Respostas:
O status de saída do pipeline é o status de saída do último comando no pipeline (a menos que a opção shell
pipefail
esteja configurada nos shells que o suportam, nesse caso, o status de saída será o do último comando no pipeline que sai com um status diferente de zero).Não é possível gerar o status de saída de um pipeline de dentro de um pipeline, já que não há como saber qual seria esse valor até que o pipeline tenha realmente terminado de executar.
O gasoduto
é absurdo, pois
echo
não lê sua entrada padrão (os pipelines são usados para passar dados entre a saída de um comando para a entrada do próximo). Oecho
também não iria imprimir o status de saída do gasoduto, mas o status de saída do comando executado imediatamente antes do pipeline.Este é um exemplo melhor:
Isso significa que um pipeline também pode ser usado com
if
:fonte
O status de saída de um tubo é o status de saída do comando à direita. O status de saída do comando esquerdo é ignorado.
(Observe que
which lss | echo $?
não mostra isso. Você executariawhich lss | true; echo $?
para mostrar isso. Emwhich lss | echo $?
,echo $?
relata o status do último comando antes deste pipeline.)A razão pela qual os shells se comportam dessa maneira é que existe um cenário bastante comum em que um erro no lado esquerdo deve ser ignorado. Se o lado direito sair (ou mais geralmente fechar sua entrada padrão) enquanto o lado esquerdo ainda estiver gravando, o lado esquerdo receberá um sinal SIGPIPE. Nesse caso, geralmente não há nada errado: o lado direito não se importa com os dados; se o papel do lado esquerdo é apenas produzir esses dados, não há problema em parar.
No entanto, se o lado esquerdo morrer por algum motivo que não seja o SIGPIPE, ou se o trabalho do lado esquerdo não for apenas produzir dados na saída padrão, um erro no lado esquerdo é um erro genuíno que deve ser relatado.
No sh simples, a única solução é usar um pipe nomeado.
No ksh, bash e zsh, você pode instruir o shell a fazer com que um pipeline saia com um status diferente de zero se algum componente do pipeline sair com um status diferente de zero. Você precisa definir a
pipefail
opção:set -o pipefail
shopt -s pipefail
setopt pipefail
(ousetopt pipe_fail
)No mksh, bash e zsh, você pode obter o status de cada componente do pipeline usando a variável
PIPESTATUS
(bash, mksh) oupipestatus
(zsh), que é uma matriz que contém o status de todos os comandos no último pipeline (uma generalização de$?
)fonte
Sim, o PIPE produz um status de saída; se você quiser o código de saída do comando antes do PIPE, poderá usar
$PIPESTATUS
De acordo com as Perguntas e respostas sobre o estouro de pilha , para imprimir o status de saída de um comando ao usar um pipe, você pode:
Ou defina pipefail com o comando
set -o pipefail
(para desativá-lo, façaset +o pipefail
) e use em$?
vez de$PIPESTATUS
.Esses comandos só funcionam depois que você os executa pelo menos uma vez; isso significa que
PIPESTATUS
só funciona quando você o executa após o comando com o pipe, assim:Você receberá 10 por
${PIPESTATUS[0]}
e 1 por${PIPESTATUS[1]}
. Consulte estas perguntas e respostas sobre U&L para obter mais informações.fonte
PIPESTATUS
contenha os status de saída dos comandos no último pipeline, seu primeiro exemplo não faz mais sentido do que osomecmd | echo $?
que Kusalananda tratou em sua resposta.false; true | echo $PIPESTATUS
imprime1
para o status de saída defalse
.|exho
que realmente está confundindoO shell avalia a linha de comando antes da execução do pipeline. Assim
$?
é o valor do último comando executado antes do pipeline. Seecho
ele é iniciado antes ou depoiswhich
é irrelevante.Agora, se sua pergunta foi especificamente sobre a propagação do status de saída, você pode estudar o comportamento padrão como este:
Como você pode ver, o status de saída de um pipeline é o status de saída de seu último comando.
fonte