エンドゴール:バックグラウンドジョブの完了を待機しているBASHスクリプトは、最初に中止されませんCtrl-c
。代わりに、Ctrl-c
終了するのに1秒必要です。
BASHビルトインがどのように機能するかはよく知っていtrap
ます。次のいずれかを行うことができます。
信号を完全に無視するために使用します(例:trap '' 2
)...または
本来の機能が起こることが許可されている信号の前に実行任意のコマンドを持っているためにそれを使用します(例えば、trap cmd 2
ここで、cmd
親スクリプトがのために中断される前に実行されますSIGINT
)
質問はこれに要約されます:
どうすれば1と2を効果的に組み合わせることができますか?つまり、信号がもたらす最終結果(1-たとえば、スクリプトのキャンセルによる停止
SIGINT
)を防止しながら、その信号に他の何かを引き起こします(2-たとえば、インクリメントaカウンター、カウンターを確認し、条件付きで警告を出力するか、終了します。
もっと簡単に言うと:
シグナルに他のことを完全に実行させるにはどうすればよいですか。ジョブを実行する前に挿入するだけではありません。
これが私が目指していることを示すためのサンプルコードです。ただし、上から1または2trap
しか実行できないため、もちろん機能しません。
#!/bin/bash
declare -i number_of_times_trap_triggered
cleanup_bg_jobs() {
number_of_times_trap_triggered+=1
if [[ ${number_of_times_trap_triggered} -eq 1 ]]; then
echo "There are background jobs still running"
echo "Hit Ctrl-c again to cancel all bg jobs & quit"
else
echo "Aborting background jobs"
for pid in ${bg_jobs}; do echo " Killing ${pid}"; kill -9 ${pid}; done
fi
}
f() { sleep 5m; }
trap cleanup_bg_jobs 2
bg_jobs=
for job in 1 2 3; do
f &
bg_jobs+=" $!"
done
wait
したがって、これはCtrl-c
1回押すと最終的に得られる出力です。
[rsaw:~]$ ./zax
^CThere are background jobs still running
Hit Ctrl-c again to cancel all bg jobs & quit
[rsaw:~]$ ps axf|tail -6
24569 pts/3 S 0:00 /bin/bash ./zax
24572 pts/3 S 0:00 \_ sleep 5m
24570 pts/3 S 0:00 /bin/bash ./zax
24573 pts/3 S 0:00 \_ sleep 5m
24571 pts/3 S 0:00 /bin/bash ./zax
24574 pts/3 S 0:00 \_ sleep 5m
もちろん、最初Ctrl-c
にジョブをクリーンアップするように変更することもできますが、それは私が望んでいることではありません。最初のトラップがトリガーされた後、BASHが終了するのを止めたい... 2回目のトラップがトリガーされるまで。
PS:BASH v4 +を搭載したターゲットプラットフォームはLinux(POSIXコンプライアンスについてはあまり気になりませんでした)です。
同僚(グレガ)が私に解決策を与えてくれました...まあ、私はそれを最初に考えていなかったなんて信じられません。
「私のアプローチは... 2番目のハンドラーがその仕事を適切に実行できるように、決して戻らない関数または何か(別の待機?)を使用して、十分に長く、場合によっては永久にそれをレイオフすることです。」
記録としてwait
は、ここでは機能しません。(再帰的です。)ただし、sleep
元のコードのcleanup_bg_jobs()
関数にコマンドを追加すると、コマンドは処理されますが、プロセスが孤立します。そこで、プロセスグループを活用して、スクリプトのすべての子が実際に強制終了されるようにしました。後世の簡略化された例:
#!/bin/bash
declare -i count=
handle_interrupt() {
count+=1
if [[ ${count} -eq 1 ]]; then
echo "Background jobs still running"
echo "Hit Ctrl-c again to cancel all bg jobs & quit"
sleep 1h
else
echo "Aborting background jobs"
pkill --pgroup 0
fi
}
f() { tload &>/dev/null; }
trap handle_interrupt 2
for job in 1 2 3; do
f &
done
wait
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加