(16の回答)
7年前に終了しました。
ソースコードを検討してください:
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;
出力:
Exit status: 1
Exit status: 0
- 変数
$exit_status
はChild.shの終了ステータスをキャプチャしているため、1
もキャプチャされます。 。 - 2番目のケースでは、
$exit_status
ティーの終了ステータス()をキャプチャしています 。
では、終了ステータスをキャプチャしてteeを使用するにはどうすればよいですか?
承認された回答:
comp.unix.shell FAQから複製(および改善)されました(FAQのそのセクションをたまたま書いたので):
cmd1|cmd2でcmd1の終了コードを取得するにはどうすればよいですか
まず、cmd1の終了コードがゼロ以外である可能性がありますが、それでも
エラーを意味するわけではないことに注意してください。これは、たとえば
cmd | head -n 1
cmd
の141(またはksh93の場合は269、yashの場合は397)の終了ステータスが表示される場合があります。 、
しかし、それはcmd
head -n 1
のときに、SIGPIPEシグナルによって中断されました 1行読んだ後に終了しました。
パイプラインの要素の終了ステータスを知るには
cmd1 | cmd2 | cmd3
zsh(およびfish 3.1+)を使用:
終了コードはpipestatus
で提供されます 特別な配列。 cmd1
終了コードは$pipestatus[1]
にあります 、cmd3
$pipestatus[3]
の終了コード 、そのため、$status
/ $?
常に$pipestatus[-1]
と同じです 。
bash付き:
終了コードはPIPESTATUS
で提供されます 特別な配列。 cmd1
終了コードは${PIPESTATUS[0]}
にあります 、cmd3
${PIPESTATUS[2]}
の終了コード 、そのため$?
常に${PIPESTATUS[-1]}
と同じです (または${PIPESTATUS[@]: -1}
4.2より古いバージョンの場合)。
シェルのような他のボーンと一緒に
トリックを使用して、終了コードをメインシェルに渡す必要があります。
パイプを使って行うことができます(2)。 cmd1
を実行する代わりに 、cmd1; echo "$?"
$を確認しますか?シェルに到達します。
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"
$ec1
の終了コード 、$ec2
、$ec3
。
POSIXシェルを使用
この関数を使用すると、簡単になります:
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"
}
次のように使用します:
run cmd1 | cmd2 | cmd3
終了コードは$pipestatus_1
にあります 、$pipestatus_2
、$pipestatus_3
および$?
右端のゼロ以外の終了ステータスです(pipefail
など) 一部のシェルのオプション)。