10

コンテクスト:

EXIT疑似信号のサブシェルとトラップを含むbashスクリプトがありますが、。の間に割り込みを適切にトラップしていませんrsync。次に例を示します。

#!/bin/bash
logfile=/path/to/file;
directory1=/path/to/dir
directory2=/path/to/dir

cleanup () {
     echo "Cleaning up!"
     #do stuff
     trap - EXIT 
}

trap '{
    (cleanup;) | 2>&1 tee -a $logfile
}' EXIT

(
    #main script logic, including the following lines:
    (exec sleep 10;);        
    (exec rsync --progress -av --delete $directory1 /var/tmp/$directory2;);

)  | 2>&1 tee -a $logfile
trap - EXIT #just in case cleanup isn't called for some reason

スクリプトの考え方は次のとおりです。重要なロジックのほとんどは、ログファイルを介してログファイルにパイプされるサブシェルで実行されるため、すべてをログに記録するためにメインロジックのすべての行teeを実行する必要はありません。teeサブシェルが終了するか、何らかの理由でスクリプトが停止すると(EXIT疑似信号はこれらすべてのケースをキャプチャする必要があります)、トラップはそれをインターセプトしてcleanup()関数を実行し、トラップを削除します。rsyncandsleepコマンド(スリープは単なる例です)は、実行中に親スクリプトを強制終了した場合にゾンビプロセスが作成されないようにするために実行されます。またexec、実行時間が長くなる可能性のある各コマンドは、独自のサブシェルにラップされます。exec終了すると、スクリプト全体が終了することはありません。

問題:

killexec / subshel​​lwrappedコマンドの実行中に(またはCTRL + Cを介して)スクリプトを中断するsleepと、トラップが正しく機能し、「クリーンアップ!」と表示されます。エコーしてログに記録しました。rsyncコマンド中にスクリプトを中断するrsyncと、endが表示され、画面に書き込みrsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(544) [sender=3.0.6]ます。その後、スクリプトは終了します。クリーンアップもトラッピングもありません。なぜ中断/殺害はrsyncトラップをトリガーしないのですか?

rsyncでスイッチを使用してみました--no-detachが、何も変わりませんでした。私はbash4.1.2、rsync 3.0.6、centOS6.2を持っています。

4

5 に答える 5

3

ポイントXからのすべての出力を、どこでも繰り返したり、すべてのサブシェルとexecをいじったりすることなく、teeにリダイレクトするだけではどうですか...(何かを見逃さなかったことを願っています)

#!/bin/bash
logfile=/path/to/file;
directory1=/path/to/dir
directory2=/path/to/dir

exec > >(exec tee -a $logfile) 2>&1

cleanup () {
     echo "Cleaning up!"
     #do stuff
     trap - EXIT 
}
trap cleanup EXIT

sleep 10
rsync --progress -av --delete $directory1 /var/tmp/$directory2
于 2012-06-04T02:14:52.877 に答える
2

に加えてset -e、私はあなたが欲しいと思いますset -E

設定されている場合、ERRのトラップは、シェル関数、コマンド置換、およびサブシェル環境で実行されるコマンドによって継承されます。このような場合、通常、ERRトラップは継承されません。

または、コマンドをサブシェルでラップする代わりに、中括弧を使用します。これにより、コマンド出力をリダイレクトできますが、現在のシェルで実行されます。

于 2012-06-04T01:21:58.120 に答える
1

トラップに INT を追加すると、割り込みが適切にキャッチされます。

trap '{
    (cleanup;) | 2>&1 tee -a $logfile
}' EXIT INT

Bash は割り込みを正しくトラップしています。ただし、これは、 が中断された場合にスクリプトが終了時にトラップするsleep理由や、 でトリガーされない理由についての質問には答えませんrsyncが、スクリプトは想定どおりに機能します。お役に立てれば。

于 2012-03-16T15:27:51.763 に答える
0

エラー時に終了するようにシェルが構成されている可能性があります。

bash # enter subshell
set -e
trap "echo woah" EXIT
sleep 4

中断するとsleep(^C)、サブシェルは終了し、その過程でset -e出力woahされます。

また、少し関係ありません: あなたtrap - EXITは (明示的に) サブシェルにいるため、クリーンアップ関数が戻った後は効果がありません。

于 2012-03-16T15:55:36.093 に答える