Um programa a seguir em um pipeline pode ver o código de saída do programa anterior?

8

Eu gostaria de fazer um pipeline de scripts do Bash como este

prog1 | prog2

de modo que prog2 possa ver o código de saída de prog1 e agir de maneira diferente com base nessas informações.

Isso é possível?

dan
fonte
Você poderia elaborar o ato de forma diferente como parte de sua pergunta?
precisa saber é
Você tem controle limitado sobre o quanto prog2progrediu quando as prog1saídas são devido ao buffer interno usado para implementar o canal e como prog1e prog2está programado.
chepner
Também olhar para [Em que ordem fazer comandos canalizada correr?] (Unix.stackexchange.com/q/37508)
DK Bose

Respostas:

4

A resposta geral é não. É possível prog2sair antes prog1mesmo do início (obviamente isso não pode acontecer se, prog2na verdade, você ler alguma entrada, o que você esperaria que estivesse fazendo se estiver usando em um pipeline). Definitivamente, é possível prog2sair antes prog1; isso acontece, por exemplo, quando prog2é um programa de pesquisa que sai assim que encontra uma correspondência, caso em que prog1ainda não terminou de produzir todos os dados.

Não há uma maneira direta prog2de recuperar o status de saída prog1ou até mesmo saber que prog1saiu. Tudo o que prog2podemos saber é que prog1fechou a extremidade do tubo, o que pode ser feito sem morrer.

Se você quiser obter o status de saída prog1de prog2, há dois métodos comuns: você pode escrevê-lo em um arquivo, ou você pode enviá-lo através do tubo. Enviar o status de saída como a última linha dos dados canalizados é uma possibilidade. Você deve certificar-se de não processar a última linha até saber que é a última linha, ou seja, até tentar ler a próxima linha.

{ prog1; echo $?; } | 

Aqui está um exemplo em que o lado direito é um filtro de texto que colore todas as linhas que contêm a palavra "erro" em vermelho. Se o lado esquerdo falhar, o lado direito sai com o mesmo status.

{ prog1; echo $?; } | awk '
    NR != 1 {
        if (line ~ /[Ee][Rr][Rr][Oo][Rr]/) print "\033[31m" line "\033[0m";
        else print line;
    }
    {line = $0}
    END {exit($0)}
'
Gilles 'SO- parar de ser mau'
fonte
Eu estava tentando fazer { command; echo ${PIPESTATUS[@]}; } | sort | ...com que o status de saída fosse o primeiro no fluxo. É tudo muito interessante!
@ illuminÉ Isso só funcionaria se ${PIPESTATUS[@]}for classificado antes de qualquer outra coisa na saída de command. Se commandimprimir vários números ou se puder imprimir texto arbitrário, você estará com problemas: não será possível distinguir sua saída da linha de status.
Gilles 'SO- stop be evil'
Obrigado, na verdade, ele só consegue classificar um status de sucesso para o topo se o comando não contiver 0 em sua saída lol. Tgif / s.
2

Embora você possa, em alguns casos especiais (ver as outras respostas), não é possível em todos os casos. Alguns programas de filtro continuam, enquanto outros retêm toda a saída, liberam-na em uma única explosão e saem.

Para um exemplo de um programa "apenas continue", grepo servidor irá, como faria tail -f /var/log/some_log_file. O uso sortem um pipeline causa uma "paralisação", pois sortele coletará entradas até que o cano na frente dele se feche. O uso xargsadiciona uma complicação adicional: os programas iniciados por xargs(podem iniciar várias instâncias) fazem parte do pipeline ou não?

Bruce Ediger
fonte
-1 porque você foi votado por racionalizar uma resposta incorreta.
ctrl-alt-Delor
@richard Huh? A resposta de Bruce está correta (embora o segundo parágrafo seja um pouco confuso).
Gilles 'SO- stop be evil'
1

A resposta: não diretamente.

@terdon ilustrou que o código de saída do comando anterior no canal deve ser enviado como um parâmetro explícito para o próximo comando.

Lembre-se de que o canal é apenas um mapeamento do STDOUT do comando anterior para o STDIN do próximo comando; os códigos de saída não são enviados para STDOUT (ou STDERR).

pepoluan
fonte
1
-1 porque você foi votado por citar uma resposta incorreta e não dizer muito mais.
ctrl-alt-Delor
bastante justo @ Richard ... Eu deveria ter checado duas vezes ... foi o que aconteceu, se eu me forço a responder a uma pergunta, quando muito cansado ...
pepoluan
1

Todo o processo, no pipeline, é iniciado antes de qualquer saída. Portanto, prog2poderia ter que obter essas informações depois de ter iniciado, também teria que adiar o processamento até prog1sair, isso poderia parar o tubo. Parece haver problemas fundamentais ao fazer o que você pede, não limitações do sistema operacional.

Você provavelmente precisa considerar um arquivo temporário ou colocar o resultado em uma variável.

Exemplo para pequena quantidade de dados, usando uma variável

tmp=$(prog1)
if test "z$PIPESTATUS" == "z0"
then
   
else
   
fi
ctrl-alt-delor
fonte
Há uma lacuna no seu raciocínio. prog2é iniciado antes da prog1conclusão em geral, mas pode haver uma maneira de receber o status de saída prog1enquanto estiver em execução.
Gilles 'SO- stop be evil'
0

Para finalizar a resposta de Gilles ,

(prog1; echo $? > /tmp/prog1.status) | prog2

é uma abordagem.  prog2poderia

  • leia a entrada padrão até o fim e leia /tmp/prog1.statusou
  • verifique a existência de /tmp/prog1.statusperiodicamente enquanto lê a entrada padrão.
Scott
fonte