トラップ Ctrl C が期待どおりに動作しません。

トラップ Ctrl C が期待どおりに動作しません。

次のコードがあります。

{
    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秒後に停止しますが、クリーンアップ関数は呼び出されません。

ファイルにうまくリダイレ​​クトするために、すべてのコードを{}に入れました。 (これを呼び出してリダイレクトするために別のスクリプトを使用しますが、スクリプトを終了してこのスクリプトに信号を伝播するのがより難しいようです。ただ次のようにすることにしました。

トラップとクリーンアップを{}ブロックの外側に配置すると、クリーンアップ関数が呼び出されますが、コードの他の部分でもそれを呼び出せる必要があるため、中かっこについて何かが欠けていると確信しています。角括弧の外側の{}ブロック内にあります。

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

ベストアンサー1

  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. スクリプトの解決策は次のとおりです。

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

b。最初に{一部のスマート構成を使用する前に、clean関数を移動してみてくださいeval(私のスクリプトでどのように機能するかを確認してください)。これが不可能な場合は、中かっこ内にプロキシ関数を作成して関数をより一般的にし、トラップの呼び出しで欠落している部分をパッチします。

おすすめ記事