(16 odpovědí)
Uzavřeno před 7 lety.
Zvažte zdrojový kód:
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;
Výstup:
Exit status: 1
Exit status: 0
- Proměnná
$exit_status
zachycuje stav ukončení Child.sh a stejně tak1
. - Ve 2. případě
$exit_status
zachycuje výstupní stav odpaliště, což je.
Jak tedy mohu zachytit stav odchodu a také použít tee?
Přijatá odpověď:
Reprodukováno (a vylepšeno) z comp.unix.shell FAQ (protože jsem náhodou napsal tuto sekci FAQ):
Jak získám výstupní kód cmd1 v cmd1|cmd2
Nejprve si uvědomte, že výstupní kód cmd1 může být nenulový a stále to
neznamená chybu. To se děje například v
cmd | head -n 1
můžete pozorovat stav ukončení 141 (nebo 269 s ksh93 nebo 397 s yash) cmd
,
ale je to proto, že cmd
byl přerušen signálem SIGPIPE, když head -n 1
ukončeno po přečtení jednoho řádku.
Chcete-li znát výstupní stav prvků potrubí
cmd1 | cmd2 | cmd3
se zsh (a fish 3.1+):
Výstupní kódy jsou uvedeny v pipestatus
speciální pole. cmd1
výstupní kód je v $pipestatus[1]
, cmd3
výstupní kód v $pipestatus[3]
, takže $status
/$?
je vždy stejný jako $pipestatus[-1]
.
s bash:
Výstupní kódy jsou uvedeny v PIPESTATUS
speciální pole. cmd1
výstupní kód je v ${PIPESTATUS[0]}
, cmd3
výstupní kód v ${PIPESTATUS[2]}
, takže $?
je vždy stejný jako ${PIPESTATUS[-1]}
(nebo ${PIPESTATUS[@]: -1}
pro verze starší než 4.2).
s jakýmikoli jinými Bourneovými mušlemi
K předání výstupních kódů do hlavního shellu musíte použít trik. Můžete to udělat
pomocí potrubí (2). Místo spouštění cmd1
, spustíte cmd1; echo "$?"
a ujistěte se
$? dostane cestu do shellu.
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"
Výstupní kódy v $ec1
, $ec2
, $ec3
.
s shellem POSIX
Tuto funkci můžete použít pro usnadnění:
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"
}
Použijte jej jako:
run cmd1 | cmd2 | cmd3
výstupní kódy jsou v $pipestatus_1
, $pipestatus_2
, $pipestatus_3
a $?
je nenulový výstupní stav zcela vpravo (jako u pipefail
možnost některých mušlí).