プロセスが終了したことを知らせるのではなく、「trap」がゼロを渡すのはなぜですか?

プロセスが終了したことを知らせるのではなく、「trap」がゼロを渡すのはなぜですか?

以下を考慮してください。

#!/bin/bash

trap 'echo $?' INT
kill -INT $$

出力:0

ここで私は130私のシステムを楽しみにしています。もちろん私がaをしたならCtrl + C私は130

HUPまたは同じ他の信号でも同様ですTERMtrap多くの信号をキャプチャする設定があると、ハンドラが呼び出された信号の正しいエラーコードで終了できないため、この動作は驚くべきことです。

#!/bin/dash

exit_abrupt() {
    exit_code=$?
    echo "Encountered an error, cleaning up..." >&2
    # *clean up*

    exit "$exit_code" # This will return 0!
}

trap exit_abrupt HUP INT TERM
kill -HUP $$

Bash、Dash、ZSHをテストしましたが、すべてこれらの動作を示しました。これがクロスシェルが機能する方法ですか? POSIXによって文書化されていますか(誰かが私に文書を教えてもらえますか?)シェルで実行するための正しい終了コードをどうやって知ることができますか?

最高POSIX ドキュメント私が読んだ内容は次のとおりです。

「$」の値は何ですか?トラップ操作の完了は、トラップが呼び出される前の値でなければなりません。

私にとっては、すべての場合に信号を伝える必要があるように聞こえますが、そうではないので、何かが欠けています。

ベストアンサー1

$?最後のコマンドの実行と待機の終了状態が含まれます。以下で見つけることができます:

$ bash -c 'trap "echo \$?" INT; sleep 10; exit'
^C130

130 は ^Csleepから SIGINT を受け取りbash、bash が戻った後にハンドラーを実行し、コマンドsleepの終了状況を印刷したため報告されました。sleep

存在する:

$ bash -c 'trap "echo \$?" INT; kill -s INT "$$"; exit'
0

killSIGINTハンドラを呼び出す前に、bashが最後に実行したコマンドであるコマンドの終了ステータスを取得できます。

$ bash -c 'trap "echo \$?" INT; (trap "" INT; sleep 3; exit 123); exit'
^C123

sleepSIGINTを無視すると、Ctrl+を押した後Cも実行中のサブシェルが返されるのを待つ必要があり、sleepハンドラはサブシェルの終了ステータス(123)を印刷します。

複数の信号に対して同じハンドラを取り付ける場合は、信号をハンドラに渡すことができます。

handler() {
  local signal="$1"
  echo "I got $signal signal"
}
for signal in INT HUP TERM QUIT; do
  trap "handler $signal" "$signal"
done

ところで、あなたは見つけることができます:

bash -c '(trap "" INT; sleep 3; exit 123); exit'

Ctrl+ で中断しようとしてもc終了状態 123 で終了しますが、これは実際に bash の設計です。詳しくは以下をご覧ください。ターミナルにctrl-cを入力したときにフォアグラウンドジョブが完了する前に終了しないのはなぜですか?

おすすめ記事