(16 Antworten)
Vor 7 Jahren geschlossen.
Betrachten Sie den Quellcode:
1. Parent.sh
#!/usr/bin/ksh
# No tee
ksh Child.sh;
exit_status=$?;
echo "Exit status: ${exit_status}"
# Using tee
ksh Child.sh | tee -a log.txt;
exit_status=$?;
echo "Exit status: ${exit_status}"
2. Child.sh
#!/usr/bin/ksh
...
exit 1;
Ausgabe:
Exit status: 1
Exit status: 0
- Variable
$exit_status
erfasst den Exit-Status von Child.sh und1
ebenfalls . - Im zweiten Fall
$exit_status
erfasst den Exit-Status von tee, also.
Wie erfasse ich also den Exit-Status und verwende auch tee?
Akzeptierte Antwort:
Reproduziert (und verbessert) aus der comp.unix.shell-FAQ (da ich zufällig diesen Abschnitt der FAQ geschrieben habe):
Wie erhalte ich den Exit-Code von cmd1 in cmd1|cmd2
Beachten Sie zunächst, dass der Exit-Code von cmd1 ungleich Null sein kann und dennoch
keinen Fehler bedeutet. Dies geschieht beispielsweise in
cmd | head -n 1
Sie könnten einen 141 (oder 269 mit ksh93 oder 397 mit yash) Exit-Status von cmd
beobachten ,
aber es liegt daran, dass cmd
wurde durch ein SIGPIPE-Signal unterbrochen, wenn head -n 1
beendet, nachdem eine Zeile gelesen wurde.
Um den Exit-Status der Elemente einer Pipeline zu kennen
cmd1 | cmd2 | cmd3
mit zsh (und fish 3.1+):
Die Exit-Codes werden im pipestatus
bereitgestellt spezielles Array. cmd1
Der Exit-Code befindet sich in $pipestatus[1]
, cmd3
Exit-Code in $pipestatus[3]
, sodass $status
/$?
ist immer dasselbe wie $pipestatus[-1]
.
mit bash:
Die Exit-Codes werden im PIPESTATUS
bereitgestellt spezielles Array. cmd1
Exitcode ist in ${PIPESTATUS[0]}
, cmd3
Exit-Code in ${PIPESTATUS[2]}
, sodass $?
ist immer dasselbe wie ${PIPESTATUS[-1]}
(oder ${PIPESTATUS[@]: -1}
für Versionen älter als 4.2).
mit anderen Bourne-ähnlichen Muscheln
Sie müssen einen Trick anwenden, um die Exit-Codes an die Haupt-Shell zu übergeben. Sie können es
mit einer Pipe(2) machen. Statt cmd1
auszuführen , führen Sie cmd1; echo "$?"
und stellen Sie
sicher, dass $? macht sich auf den Weg zur Shell.
exec 3>&1
code=`
# now, inside the backticks, fd4 goes to the pipe
# whose other end is read and stored in $code for
# later evaluation; fd1 is the normal standard output
# preserved the line before with exec 3>&1
exec 4>&1 >&3 3>&-
{
cmd1 4>&-; echo "ec1=$?;" >&4
} | {
cmd2 4>&-; echo "ec2=$?;" >&4
} | cmd3 4>&-
echo "ec3=$?;" >&4
`
exec 3>&-
eval "$code"
Exit-Codes in $ec1
, $ec2
, $ec3
.
mit einer POSIX-Shell
Sie können diese Funktion verwenden, um es einfacher zu machen:
run() {
j=1
while eval "${pipestatus_$j+:} false"; do
unset "pipestatus_$j"
j=$(($j+1))
done
j=1 com= k=1 l=
for arg do
case $arg in
('|')
com="$com {
$l "'3>&-
echo "pipestatus_'$j'=$?" >&3
} 4>&- |'
j=$(($j+1)) l=;;
(*)
l="$l "${$k}""
esac
k=$(($k+1))
done
com="$com $l"' 3>&- >&4 4>&-
echo "pipestatus_'$j'=$?"'
{ eval "$(exec 3>&1; eval "$com")"; } 4>&1
j=1
ret=0
while eval "${pipestatus_$j+:} false"; do
eval '[ "$pipestatus_'"$j"'" -eq 0 ] || ret=$pipestatus_'"$j"
j=$(($j+1))
done
return "$ret"
}
Verwenden Sie es als:
run cmd1 | cmd2 | cmd3
Exit-Codes befinden sich in $pipestatus_1
, $pipestatus_2
, $pipestatus_3
und $?
ist der Exit-Status ganz rechts ungleich Null (wie beim pipefail
Option einiger Muscheln).