Como capturar o status de saída de um comando não final em um pipeline? [duplicado]

4

Eu quero capturar o status de saída de um comando que ocorre em algum lugar em um pipeline antes da última posição. Por exemplo, se o pipeline é algo como

command_1 ... | command_2 ... | command_3 ... | ... | command_n

... Gostaria de saber como capturar o status de saída de command_1 , ou de command_2 , ou de command_3 , etc. (Capturar o status de saída de command_n é trivial, é claro .)

Além disso, caso isso seja importante, este pipeline está ocorrendo dentro de uma função de shell zsh.

Eu tentei capturar o status de saída de command_1 com algo como

function_with_pipeline () {

    local command_1_status=-999999  # sentinel value

    { command_1 ...; command_1_status=$? } | command_2 ... | ... | command_n
    ...

}

... mas depois de executar o pipeline, o valor da variável command_1_status ainda era o valor sentinela.

FWIW, aqui está um exemplo de trabalho, onde o pipeline tem apenas dois comandos:

foo ... | grep ...

foo é uma função definida por causa deste exemplo, da seguinte forma:

foo () {

    (( $1 & 1 )) && echo "a non-neglible message"
    (( $1 & 2 )) && echo "a negligible message"
    (( $1 & 4 )) && echo "error message" >&2

    return $(( ( $1 & 4 ) >> 2 ))
}

O objetivo é capturar o status de saída da chamada para foo no pipeline.

A função function_with_pipeline implementa a estratégia (ineficiente) descrita acima para fazer isso:

function_with_pipeline () {

    local foo_status=-999999  # sentinel value

    { foo $1; foo_status=$? } | grep -v "a negligible message"

    printf '%d\ndesired: %d; actual: %d\n\n' $1 $(( ( $1 & 4 ) >> 2 )) $foo_status

}

O loop abaixo exerce a função function_with_pipeline . A saída mostra que o valor da variável local foo_status não é diferente de como começou.

for i in $(seq 0 7)
do
    function_with_pipeline $i
done
# 0
# desired: 0; actual: -999999
# 
# a non-neglible message
# 1
# desired: 0; actual: -999999
# 
# 2
# desired: 0; actual: -999999
# 
# a non-neglible message
# 3
# desired: 0; actual: -999999
# 
# error message
# 4
# desired: 1; actual: -999999
# 
# error message
# a non-neglible message
# 5
# desired: 1; actual: -999999
# 
# error message
# 6
# desired: 1; actual: -999999
# 
# error message
# a non-neglible message
# 7
# desired: 1; actual: -999999
#

Eu obtenho os mesmos resultados se omitir a declaração local na definição de foo_status .

    
por kjo 22.10.2016 / 16:25

2 respostas

4

Existe uma matriz especial pipestatus para essa em zsh , por isso tente

command_1 ... | command_2 ... | command_3

e

echo $pipestatus[1] $pipestatus[2] $pipestatus[3]

e a razão pela qual sua abordagem não funciona é porque cada pipe é executado em subshell separado, com suas próprias variáveis que são destruídas quando você sai da sub-rede.

Apenas para referência, é PIPESTATUS (com letras maiúsculas) em bash .

    
por 22.10.2016 / 16:52
2

mispipe funciona em qualquer shell. A sintaxe (em comparação com um pipe normal) funciona assim:

mispipe true false ; echo $?  # returns exit code of 1st command 'true'
true | false ; echo $?  # returns exit code of 2nd command 'false'

Saída:

0
1

O que fazer se houver mais de dois programas:

# this still returns exit code of 1st command 'true'
mispipe true 'false | false | false' ; echo $?

Saída:

0

Apesar da falta de | visível, ele ainda se comporta como um tubo:

yes | mispipe head 'wc -c'

Saída:

     20
    
por 22.10.2016 / 17:55

Tags