(16 jawaban)
Tutup 7 tahun yang lalu.
Pertimbangkan Kode sumber:
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;
Keluaran:
Exit status: 1
Exit status: 0
- Variabel
$exit_status
menangkap status keluar Child.sh dan begitu juga1
. - Dalam kasus kedua,
$exit_status
sedang menangkap status keluar dari tee, yaitu.
Jadi bagaimana cara menangkap status keluar dan juga menggunakan tee?
Jawaban yang Diterima:
Direproduksi (dan ditingkatkan) dari FAQ comp.unix.shell (karena saya kebetulan telah menulis bagian FAQ itu):
Bagaimana cara mendapatkan kode keluar cmd1 di cmd1|cmd2
Pertama, perhatikan bahwa kode keluar cmd1 mungkin bukan nol dan tetap tidak
berarti kesalahan. Ini terjadi misalnya di
cmd | head -n 1
anda mungkin mengamati status keluar 141 (atau 269 dengan ksh93, atau 397 dengan yash) dari cmd
,
tapi itu karena cmd
diinterupsi oleh sinyal SIGPIPE saat head -n 1
dihentikan setelah membaca satu baris.
Untuk mengetahui status keluar dari elemen pipa
cmd1 | cmd2 | cmd3
dengan zsh (dan ikan 3.1+):
Kode keluar disediakan di pipestatus
susunan khusus. cmd1
kode keluar ada di $pipestatus[1]
, cmd3
keluar kode di $pipestatus[3]
, sehingga $status
/$?
selalu sama dengan $pipestatus[-1]
.
dengan bash:
Kode keluar disediakan di PIPESTATUS
susunan khusus. cmd1
kode keluar ada di ${PIPESTATUS[0]}
, cmd3
kode keluar di ${PIPESTATUS[2]}
, sehingga $?
selalu sama dengan ${PIPESTATUS[-1]}
(atau ${PIPESTATUS[@]: -1}
untuk versi yang lebih lama dari 4.2).
dengan cangkang seperti Bourne lainnya
Anda perlu menggunakan trik untuk meneruskan kode keluar ke shell utama. Anda dapat melakukannya
menggunakan pipa(2). Alih-alih menjalankan cmd1
, Anda menjalankan cmd1; echo "$?"
dan membuat
yakin $? menuju ke cangkangnya.
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"
Keluar dari kode di $ec1
, $ec2
, $ec3
.
dengan cangkang POSIX
Anda dapat menggunakan fungsi ini untuk mempermudah:
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"
}
Gunakan sebagai:
run cmd1 | cmd2 | cmd3
kode keluar ada di $pipestatus_1
, $pipestatus_2
, $pipestatus_3
dan $?
adalah status keluar bukan nol paling kanan (seperti dengan pipefail
pilihan beberapa shell).