
Quero capturar o status de saída de um comando que ocorre em algum lugar de um pipelineantesa última posição. Por exemplo, se o pipeline for algo como
command_1 ... | command_2 ... | command_3 ... | ... | command_n
...Eu 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 seja importante, esse pipeline está ocorrendo dentro de uma função shell zsh.
Tentei capturar o status de saída 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 command_1_status
variável ainda era o valor sentinela.
FWIW, aqui está um exemplo prático, onde o pipeline possui apenas dois comandos:
foo ... | grep ...
foo
é uma função definida para este exemplo, assim:
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 foo
no pipeline.
A função function_with_pipeline
implementa a estratégia (em última análise ineficaz) que descrevi 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 exercita a function_with_pipeline
função. 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
#
Obtenho os mesmos resultados se omitir a local
declaração na definição de foo_status
.
Responder1
Existe um array especial pipestatus
para isso zsh
, então 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 um subshell separado, com suas próprias variáveis que são destruídas quando você sai do subshell.
Apenas para referência, está PIPESTATUS
(com letras maiúsculas) no formato bash
.
Responder2
mispipe
funciona em qualquer shell. A sintaxe (comparada a um canal 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 um visível |
, ele ainda se comporta como um tubo deveria:
yes | mispipe head 'wc -c'
Saída:
20