bash 3と4のSIGINT処理の違い

bash 3と4のSIGINT処理の違い

Bash 4.3ではうまく動作するスクリプトがありますが、Bash 3.2では予期しない動作が発生します。簡略化されたバージョンは次のとおりです。

set -o errexit -o pipefail

task() {
    local name=${1}
    local duration=${2}
    trap 'echo "[${SECONDS} secs] ${name}: SIGINT"; exit 255' INT
    echo "[${SECONDS} secs] ${name}: Running"
    sleep "${duration}"
    echo "[${SECONDS} secs] ${name}: Done"
}

trap 'echo "[${SECONDS} secs] SIGINT"; exit 255' INT
task 'Task 1' 5 &
task 'Task 2' 5 &
wait
echo "[${SECONDS} secs] Done"

以下は、bash 4.3(4.3.42(1)-release)を使用してCTRL-Cを2秒間実行した後の出力です。

[0 secs] Task 1: Running
[0 secs] Task 2: Running
^C[2 secs] SIGINT
[2 secs] Task 2: SIGINT
[2 secs] Task 1: SIGINT
prompt>

同じですが、bash 3.2(3.2.57(1) - リリース)の場合:

[0 secs] Task 1: Running
[0 secs] Task 2: Running
^C[2 secs] SIGINT
prompt> [5 secs] Task 2: Done
[5 secs] Task 1: Done

bash 3.2で上記のスクリプトが正しく機能しないという既知の問題はありますか?回避策がありますか?

私が試したいくつかのことは次のとおりです。

  • 親エントリにはシグナルハンドラはありません。

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] Task 2: SIGINT
    [2 secs] Task 1: SIGINT
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • 信号ハンドラはまったくありません。

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • 親のシグナルハンドラはSIGINT()を使用してプロセスグループを終了しますkill -INT -- -$$

    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    [2 secs] Task 2: SIGINT
    [2 secs] Task 1: SIGINT
    prompt>
    
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • 親のシグナルハンドラは、SIGTERM(SIGTERMをキャプチャするアクション)を使用してプロセスグループを終了します。

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    [2]    92813 terminated  bash minimal_example.sh
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    Terminated: 15
    Terminated: 15
    [2 secs] Task 2: SIGTERM
    [2 secs] Task 1: SIGTERM
    [1]    92836 terminated  /bin/bash minimal_example.sh
    prompt>
    

最後は3.2で正常に動作するのに最も近いです。しかし、4.3では、同じコードが異なる動作をします。

答え1

ユーザーは、多くのbash場合、makeユーザーに影響を与える既知の問題の被害者である可能性があります。

Bash 4をチェックしていませんが、bash 3スクリプト内でジョブ制御が誤って実行されています。これにより、^Cコマンドが対話型でなくても、子プロセスが別々のプロセスグループで実行されるため、簡単に終了しない複数のサブディレクトリループを含むメイクファイルが生成されることがよくあります。

smake回避策を含め/bin/shbashSIGINTを現在実行中のコマンドのプロセスグループに明示的に渡します。ただし、これは使用されますC

サブプロセスグループを取得する標準のUNIXコマンドがないため、スクリプトの一般的なシェルを使用して同じ機能を実行することはできません。

関連情報