Bashリダイレクト奇妙な動作

Bashリダイレクト奇妙な動作

興味深い結果が出たら、終了コード、リダイレクト、およびケースの説明を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 1maincaseステートメントを呼び出すと、cleanup関数はそのステートメントのリダイレクトを継承します。

標準出力に何も印刷しない短い例:

cleanup () {
        echo bye
}

trap cleanup EXIT

exit >/dev/null

>/dev/nullスクリプトの出力を取得するには削除してくださいbye

結果のトレース出力はset -x標準エラーストリームに書き込まれ、コードは/dev/nullそのストリームもリダイレクトします。つまり、関数case宣言ははい実行されますが、スクリプトのすべての出力を削除するため、その出力は表示されず、トレースecho出力も表示されません。

さらに、他のいくつかのシェル(例えば、およびdashkshはこのようには機能しません。

シェルでこの問題を解決するには、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

シェルによって割り当てられ割り当てられた記述子はfd10個以上です。

sh常にそうではないため、実行可能ファイルを明示的に呼び出すように-linebashも変更しました。#!bash

これを実行してください:

$ ./script
+ exec
+ trap cleanup EXIT
message 1

おすすめ記事