
Ich möchte den Beendigungsstatus eines Befehls erfassen, der irgendwo in einer Pipeline ausgeführt wirdVordie letzte Position. Wenn die Pipeline beispielsweise so etwas ist wie
command_1 ... | command_2 ... | command_3 ... | ... | command_n
... Ich möchte wissen, wie der Beendigungsstatus von command_1
, oder von command_2
, oder von command_3
usw. erfasst wird. (Das Erfassen des Beendigungsstatus von command_n
ist natürlich trivial.)
Falls es von Bedeutung ist: Diese Pipeline erfolgt innerhalb einer ZSH-Shell-Funktion.
Ich habe versucht, den Beendigungsstatus command_1
mit etwas wie zu erfassen
function_with_pipeline () {
local command_1_status=-999999 # sentinel value
{ command_1 ...; command_1_status=$? } | command_2 ... | ... | command_n
...
}
...aber nach dem Ausführen der Pipeline war der Wert der command_1_status
Variablen immer noch der Sentinel-Wert.
Hier ist ein funktionierendes Beispiel, bei dem die Pipeline nur zwei Befehle hat:
foo ... | grep ...
foo
ist eine Funktion, die für dieses Beispiel wie folgt definiert ist:
foo () {
(( $1 & 1 )) && echo "a non-neglible message"
(( $1 & 2 )) && echo "a negligible message"
(( $1 & 4 )) && echo "error message" >&2
return $(( ( $1 & 4 ) >> 2 ))
}
Das Ziel besteht darin, den Beendigungsstatus des Aufrufs foo
in der Pipeline zu erfassen.
Die Funktion function_with_pipeline
implementiert dazu die (letztlich wirkungslose) Strategie, die ich oben beschrieben habe:
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
}
Die folgende Schleife führt die function_with_pipeline
Funktion aus. Die Ausgabe zeigt, dass der Wert der lokalen Variable foo_status
am Ende nicht anders ist als am Anfang.
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
#
Ich erhalte die gleichen Ergebnisse, wenn ich die local
Deklaration in der Definition von weglasse foo_status
.
Antwort1
pipestatus
Dafür gibt es ein spezielles Array in zsh
. Versuchen Sie es also
command_1 ... | command_2 ... | command_3
Und
echo $pipestatus[1] $pipestatus[2] $pipestatus[3]
und der Grund, warum Ihr Ansatz nicht funktioniert, liegt darin, dass jede Pipe in einer separaten Untershell mit ihren eigenen Variablen ausgeführt wird, die zerstört werden, sobald Sie die Untershell verlassen.
Nur als Referenz, es steht PIPESTATUS
(mit Großbuchstaben) in bash
.
Antwort2
mispipe
funktioniert in jeder Shell. Die Syntax (im Vergleich zu einer normalen Pipe) funktioniert folgendermaßen:
mispipe true false ; echo $? # returns exit code of 1st command `true`
true | false ; echo $? # returns exit code of 2nd command `false`
Ausgabe:
0
1
Was tun, wenn mehr als zwei Programme vorhanden sind:
# this still returns exit code of 1st command `true`
mispipe true 'false | false | false' ; echo $?
Ausgabe:
0
Obwohl kein sichtbares Zeichen vorhanden ist |
, verhält es sich dennoch so, wie es sich für eine Pipe gehört:
yes | mispipe head 'wc -c'
Ausgabe:
20