興味深い結果が出たら、終了コード、リダイレクト、およびケースの説明をstdout
キャプチャするのが忙しく、stderr
誰かがこれを明らかにできることを願っています。
私はbash 5.1.16を使用しています。
このブロックは、私が見ているアクションを複製するために使用できます。
#!/bin/sh -x
cleanup () {
case $? in
1) echo "message 1" ;;
9) echo "message 2" ;;
esac
}
trap cleanup EXIT
case 0 in
0) exit 1 ;;
2) echo "yay" ;;
esac > /dev/null 2>&1
xtrace出力> /dev/null 2>&1
:
+ trap cleanup EXIT
以下のないxtrace出力> /dev/null 2>&1
:
+ trap cleanup EXIT
+ case 0 in
+ exit 1
+ cleanup
+ case $? in
+ echo 'message 1'
message 1
ここで何が起こっているのでしょうか?リダイレクトによって Case 文がまったく実行されないのはなぜですか?
ベストアンサー1
トラップは、EXIT
呼び出されるとリダイレクトを介して行われます。コードでexit 1
maincase
ステートメントを呼び出すと、cleanup
関数はそのステートメントのリダイレクトを継承します。
標準出力に何も印刷しない短い例:
cleanup () {
echo bye
}
trap cleanup EXIT
exit >/dev/null
>/dev/null
スクリプトの出力を取得するには削除してくださいbye
。
結果のトレース出力はset -x
標準エラーストリームに書き込まれ、コードは/dev/null
そのストリームもリダイレクトします。つまり、関数case
宣言ははい実行されますが、スクリプトのすべての出力を削除するため、その出力は表示されず、トレースecho
出力も表示されません。
さらに、他のいくつかのシェル(例えば、およびdash
)ksh
はこのようには機能しません。
シェルでこの問題を解決するには、bash
スクリプトの先頭に標準エラーファイル記述子をコピーして、関数で明示的に使用できますcleanup
。私はこれが次に使用されると仮定するので、標準エラーストリームを使用しています。診断情報。
あなたのコードと追加:
#!/bin/bash -x
exec {fd}>&2
cleanup () {
case $? in
1) echo "message 1" ;;
9) echo "message 2" ;;
esac >&$fd
}
trap cleanup EXIT
case 0 in
0) exit 1 ;;
2) echo "yay" ;;
esac > /dev/null 2>&1
シェルによって割り当てられ割り当てられた記述子はfd
10個以上です。
sh
常にそうではないため、実行可能ファイルを明示的に呼び出すように-linebash
も変更しました。#!
bash
これを実行してください:
$ ./script
+ exec
+ trap cleanup EXIT
message 1