web-dev-qa-db-ja.com

トラップctrlcが期待どおりに機能しない

私は次のようなコードを持っています:

{
    trap cleanup SIGHUP SIGINT SIGTERM

    function executed() {
        if [ ${1} -ne 0 ]
        then
            echo "Failed!"
            cleanup
            exit 
        else
            echo "Succeeded!"
        fi
    }

    function cleanup() {
        echo "Cleaning up ..."
        # deleting some files and stuff like that
    }

    bunch of code ...
    ...

} 2>&1 | while IFS= read -r line; do echo "$(date) $line"; done \
>> ldapfe_graceful_$(date '+%Y_%m_%d__%H_%M_%S').log 

これに関する会社の方針がよくわからないため、すべてのコードを貼り付けることはできませんが、最も重要な部分はそこにあります。

このスクリプトの実行中にCtrl + cを押すと、すぐに停止するか、少し^ Cが表示され、5〜10秒後に停止しますが、クリーンアップ関数が呼び出されることはありません。

すべてのコードを{}内に配置して、ファイル内で適切にリダイレクトしました(別のスクリプトを使用してこれを呼び出し、リダイレクトを実行しましたが、それを強制終了して信号をこのコードに伝播するのは難しいようです。ここでは、すべてを中括弧で囲むことにしました)。

{}ブロックの外側にトラップとクリーンアップを配置すると、クリーンアップ関数が呼び出されるため、中括弧に関して何かが欠けていると確信していますが、コードの他の部分もそれを呼び出すことができるはずであり、次の場合は不可能です。 {}中括弧の外側にあります。

編集:クリーンアップ関数の後にトラップを宣言しようとしましたが、変更はありません。

2
Luka
  1. コードの他の部分は、{}中括弧の内側または外側に関係なく、実際の呼び出しの前に宣言されている限り(実際には、以前のスクリプト行に関するものではない)、クリーンアップ関数を呼び出すことができるはずです。またはそれより低いbashシェルレベル($BASH_SUBSHELL)。

  2. (編集済み)トラップがすでに宣言されていて、同じまたはより低いサブシェルレベルで宣言する必要がある場合は、トラップを呼び出すことができます。どうやら、あなたがそれを実行すると以下のコードが示すように、信号はカスケードダウンされます。

#!/usr/bin/env bash

trap "echo ok 0" 2

(
    echo subshell: $BASH_SUBSHELL   
    trap "echo ok 1" 2
    (
        echo subshell: $BASH_SUBSHELL   
        trap "echo ok 2" 2;
        sleep 100
        #now test the trap
    )
)

結果:

subshell: 0
subshell: 1
subshell: 2
^Cok 2
ok 1
ok 0

しかし、それはパイプではありません:

#!/bin/bash

trap "echo ok 0" 2

{
echo $BASH_SUBSHELL
trap "echo ok 1" 2
} | \
    {
        trap "echo ok 2" 2
        read line; echo $line;
        sleep 100
        #now Ctrl-c
    }

結果:

1
^Cok 2
ok 0
  1. 中括弧は無名関数を構成します。この関数はbashシェルレベルを維持しますが、すべてのコンテキストで維持されるわけではありません。

説明のために、以下のスクリプトを分析してください。ターミナルで実行して、何が生成されるかを確認します。

#!/bin/bash

k=k
msg='echo line: $LINENO, \$k: $k, BASH_SUBSHELL: $BASH_SUBSHELL'

eval $msg

{
    k=a
    eval $msg
} &

sleep 1
#job %1 should be done by now
jobs
eval $msg

{
    k=b
    eval $msg
} | {
    read line; echo $line;
    eval $msg
}

eval $msg

{
    k=c
    eval $msg
}

eval $msg

{ trap 'echo -e "\nterminating"; exit;' 2;}

sleep 100 #try out the trap by hitting Ctrl-c
  1. スクリプトの解決策は次のとおりです。

a。最初の{の前にトラップを移動します。

b。 evalのようないくつかのスマートな構造を使用して、最初の{の前にクリーンアップ関数を移動してみてください(スクリプトでその動作を参照してください)。不可能な場合は、中括弧内のプロキシ関数をそれらの前のより一般的な関数に構築し、トラップ内の呼び出しで欠落しているものにパッチを適用してみてください。

1
user147505