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

8

Eu gostaria de fazer um pipeline de scripts Bash como este

prog1 | prog2

tal que prog2 pode ver o código de saída do prog1 e agir de forma diferente com base nessa informação.

Isso é possível?

    
por dan 07.03.2014 / 16:33

5 respostas

4

A resposta geral é não. É possível que prog2 saia antes que prog1 seja iniciado (obviamente, isso não pode acontecer se prog2 realmente ler alguma entrada, o que você esperaria que fizesse se estivesse sendo usada em um pipeline). É definitivamente possível que prog2 saia antes de prog1 ; isso acontece por exemplo quando prog2 é um programa de pesquisa que sai assim que encontra uma correspondência, caso em que prog1 pode não ter terminado de produzir todos os dados ainda.

Não há nenhuma maneira direta de prog2 recuperar o status de saída de prog1 ou mesmo saber que prog1 foi encerrado. Tudo o que o prog2 pode saber é que prog1 fechou a ponta do tubo, o que ele pode fazer sem morrer.

Se você deseja obter o status de saída de prog1 de prog2 , há dois métodos comuns: você pode gravá-lo em um arquivo ou enviá-lo pelo canal. Enviar o status de saída como a última linha dos dados enviados é uma possibilidade. Você precisa se certificar de não processar a última linha até saber que é a última linha, ou seja, até tentar ler a próxima linha.

{ prog1; echo $?; } | …

Veja 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 "3[31m" line "3[0m";
        else print line;
    }
    {line = $0}
    END {exit($0)}
'
    
por 08.03.2014 / 01:50
2

Embora você possa, em alguns casos especiais (ver as outras respostas), não pode em todos os casos. Alguns programas de filtragem continuarão funcionando, enquanto outros manterão toda a saída, soltando-a em uma única explosão e, em seguida, sairão.

Para um exemplo de programa "continue funcionando", grep será o servidor, assim como tail -f /var/log/some_log_file . Usar sort em um pipeline causa um "stall", pois sort coletará entrada até que o tubo na frente dele seja fechado. Usar xargs adiciona uma complicação adicional: os programas são iniciados por xargs (pode iniciar muitas instâncias) parte do pipeline ou não?

    
por 07.03.2014 / 17:24
1

A resposta: não diretamente.

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

Lembre-se de que o pipe é meramente 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).

    
por 07.03.2014 / 17:17
1

Todo o processo, no pipeline, é iniciado antes de qualquer saída. Portanto prog2 poderia ter que obter essa informação depois de iniciada, ela também teria que adiar o processamento até que prog1 tivesse saído, isso poderia parar o pipe. Parece haver problemas fundamentais em fazer o que você pede, não em 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
    
por 07.03.2014 / 18:04
0

Para terminar a resposta de Gilles ,

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

é uma abordagem. prog2 poderia

  • leia a entrada padrão até o final e leia /tmp/prog1.status ou
  • verifique a existência de /tmp/prog1.status periodicamente durante a leitura da entrada padrão.
por 11.07.2014 / 20:16