(16 risposte)
Chiuso 7 anni fa.
Considera il codice sorgente:
#!/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}"
#!/usr/bin/ksh
...
exit 1;
Risultato:
Exit status: 1
Exit status: 0
- Variabile
$exit_status
sta acquisendo lo stato di uscita di Child.sh, così come1
. - Nel 2° caso,
$exit_status
sta acquisendo lo stato di uscita di tee, che è.
Quindi, come posso acquisire lo stato di uscita e utilizzare anche tee?
Risposta accettata:
Riprodotto (e migliorato) dalle FAQ di comp.unix.shell (dato che ho scritto quella sezione delle FAQ):
Come ottengo il codice di uscita di cmd1 in cmd1|cmd2
Innanzitutto, tieni presente che il codice di uscita cmd1 potrebbe essere diverso da zero e comunque non
significa un errore. Questo accade ad esempio in
cmd | head -n 1
potresti osservare uno stato di uscita 141 (o 269 con ksh93 o 397 con yash) di cmd
,
ma è perché cmd
è stato interrotto da un segnale SIGPIPE quando head -n 1
terminato dopo aver letto una riga.
Per conoscere lo stato di uscita degli elementi di una pipeline
cmd1 | cmd2 | cmd3
con zsh (e fish 3.1+):
I codici di uscita sono forniti in pipestatus
matrice speciale. cmd1
il codice di uscita è in $pipestatus[1]
, cmd3
codice di uscita in $pipestatus[3]
, in modo che $status
/$?
è sempre lo stesso di $pipestatus[-1]
.
con bash:
I codici di uscita sono forniti nel PIPESTATUS
matrice speciale. cmd1
il codice di uscita è in ${PIPESTATUS[0]}
, cmd3
codice di uscita in ${PIPESTATUS[2]}
, quindi $?
è sempre uguale a ${PIPESTATUS[-1]}
(o ${PIPESTATUS[@]: -1}
per versioni precedenti alla 4.2).
con qualsiasi altro tipo di shell Bourne
Devi usare un trucco per passare i codici di uscita alla shell principale. Puoi farlo
usando una pipe(2). Invece di eseguire cmd1
, esegui cmd1; echo "$?"
e assicurati
$? si fa strada verso la 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"
Codici di uscita in $ec1
, $ec2
, $ec3
.
con una shell POSIX
Puoi utilizzare questa funzione per semplificare:
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"
}
Usalo come:
run cmd1 | cmd2 | cmd3
i codici di uscita sono in $pipestatus_1
, $pipestatus_2
, $pipestatus_3
e $?
è lo stato di uscita diverso da zero più a destra (come con pipefail
opzione di alcune shell).