「Trap...INT TERM EXIT」は本当に必要ですか?

「Trap...INT TERM EXIT」は本当に必要ですか?

traptrap ... INT TERM EXITクリーニング作業の多くの例。しかし、3つのシグスペックをすべてリストすることは本当に必要ですか?

マニュアルによると:

SIGNAL_SPECがEXIT(0)ARGの場合、シェルを終了したときに実行されます。

SIGINTこれは、スクリプトが正常に完了したか、または受け取ったために適用されると思いますSIGTERM。実験を通して私の信念も確認された。

$ cat ./trap-exit
#!/bin/bash
trap 'echo TRAP' EXIT
sleep 3
$ ./trap-exit & sleep 1; kill -INT %1
[1] 759
TRAP
[1]+  Interrupt               ./trap-exit
$ ./trap-exit & sleep 1; kill -TERM %1
[1] 773
TRAP
[1]+  Terminated              ./trap-exit

それでは、なぜそれほど多くの例がそれらをすべてリストするのでしょうかINT TERM EXIT。それとも私が何かを見逃しているのか、EXIT足の裏がそれを見逃す場合があるのか​​?

答え1

はい、少し違います。

EnterSIGINTこのスクリプトは押すか送信すると終了しますSIGTERM

trap '' EXIT
echo ' --- press ENTER to close --- '
read response

[次へ]をクリックするとスクリプトが終了しますEnter

trap '' EXIT INT TERM
echo ' --- press ENTER to close --- '
read response

*テスト対象シェン吹くジッシュ。 (これ以上適用されません。シェントラップ実行コマンドを追加するとき)


そして@Shawnが言ったことは次のとおりです。禁煙健康増進協会そしてスプリントキャプチャ信号を使用しないでくださいEXIT

EXITしたがって、強力な信号処理のために完全に捕捉するのを避け、次のものを使用することをお勧めします。

cleanup() {
    echo "Cleaning stuff up..."
    exit
}

trap cleanup INT TERM
echo ' --- press ENTER to close --- '
read var
cleanup

答え2

これPOSIX仕様EXITトラップが実行される条件の説明はあまりありませんが、実行時に環境がどのように見えるかを説明します。

Busyboxのashシェルでは、トラップ終了テストはSIGINTまたはSIGTERMのため終了する前に「TRAP」をエコーし​​ません。このように動作しない他のシェルがあると思います。

# /tmp/test.sh & sleep 1; kill -INT %1
# 
[1]+  Interrupt                  /tmp/test.sh
# 
# 
# /tmp/test.sh & sleep 1; kill -TERM %1
# 
[1]+  Terminated                 /tmp/test.sh
# 

答え3

問題があるため、最後の回答を改善するには:

# Our general exit handler
cleanup() {
    err=$?
    echo "Cleaning stuff up..."
    trap '' EXIT INT TERM
    exit $err 
}
sig_cleanup() {
    trap '' EXIT # some shells will call EXIT after the INT handler
    false # sets $?
    cleanup
}
trap cleanup EXIT
trap sig_cleanup INT QUIT TERM

上記は次のとおりです。

テスト中にINTおよびTERMハンドラは終了しません。エラーを処理した後、シェルは終了ステータスを返します(驚きではありません)。そのため、清掃後は必ず終了をさせ、信号がある場合は常にエラーコードを使用します(その他正常終了の場合はエラーコードを保持します)。

Bashを使用すると、INTハンドラで終了するとEXITハンドラも呼び出されるようになり、終了ハンドラを解放して直接呼び出しました(動作に関係なくすべてのシェルで動作します)。

シェルスクリプトが一番下に到達する前にシャットダウンできるため、シャットダウンをキャッチします。構文エラー、-e、および0以外の戻り値の設定、単に終了を呼び出します。理解するためにシェルスクリプトに頼ることはできません。

一度試したことがない場合は、SIGQUITはCtrl-\です。追加のコアダンプを提供します。だから少しぼやけていても入れておくのも価値があると思います。

過去の経験によれば、私のように常にCtrl-Cを数回押すと、シェルスクリプトのクリーンアップ部分を途中で捉えることができます。 。

答え4

達成する目標とターゲットシェルによって異なります。bashたぶんそれだけを使うことができるからですEXIT。しかし、すべての殻ではありませんEXIT/でハンドラを呼び出します。SIGINTSIGTERM

これを行うには、複数の信号に対してハンドラ(trap '...' INT EXIT)を設定しますが、複数回呼び出すことができます。

$ bash -c 'trap "echo trap" INT EXIT; sleep 3' & pid=$!; sleep 1; kill -INT $pid; wait
[1] 276923
trap
trap
[1]+  Done                    bash -c 'trap "echo trap" INT EXIT; sleep 3'

したがって、文章を書くときにこの点を念頭に置いたり試したりすることができます。今後EXITすべてをハンドラに委ねる:

$ bash -c 'trap "exit 123" INT; trap "echo EXIT \$?" EXIT; sleep 3' & pid=$!; sleep 1; kill -INT $pid; wait
[1] 286229
EXIT 123
[1]+  Exit 123                bash -c 'trap "exit 123" INT; trap "echo EXIT \$?" EXIT; sleep 3'

SIGINTしかし、次のハンドラを構築すると、キルスクリプトSIGINT:

a.sh:

trap 'exit 123' INT
trap 'echo EXIT $?; trap - INT; kill -INT $$' EXIT
sleep 3
$ bash h.sh & pid=$!; sleep 1; kill -INT $pid; wait $pid
[1] 236263
EXIT 123
[1]+  Interrupt               bash h.sh

そしてDebian < 10(dash < 0.5.10スクリプトを終了するように指示する(そうであれば)通過できない

私が思いついた解決策は次のとおりです。

set -eu
cleanup() {
    echo "cleanup ($1)"
    trap - INT TERM EXIT  # avoid reexecuting handlers
    if [ "$1" = 130 ]; then
        kill -INT $$
    elif [ "$1" = 143 ]; then
        kill -TERM $$
    else
        exit "$1"
    fi
}
trap 'cleanup 130' INT
trap 'cleanup 143' TERM
trap 'cleanup $?' EXIT

if [ "${1-}" = fail ]; then
    no-such-command
fi
sleep 3
$ bash f.sh; echo $?
cleanup (0)
0

$ bash f.sh fail; echo $?
f.sh: line 20: no-such-command: command not found
cleanup (127)
127

$ bash f.sh & pid=$!; sleep 1; kill -INT $pid; wait $pid
[1] 282422
cleanup (130)
[1]+  Interrupt               bash f.sh

$ bash f.sh & pid=$!; sleep 1; kill -TERM $pid; wait $pid
[1] 282458
cleanup (143)
[1]+  Terminated              bash f.sh

テスト対象:

  • bash:5.1.8
  • ダッシュ: 0.5.10, 0.5.8,0.5.7
  • Alpine Linux 3.14(busybox

関連情報