次のプロセス実行構造があります。
script0.sh
script1.sh
script2.sh
script3.sh
重要性:
- script0.sh は script1.sh を実行します。
- script1.sh は script2.sh と script3.sh を実行します。
理想的には、script1.shにクリーンアップとシャットダウンを実行するトラップハンドラを持ちたいと思います。
何らかの理由で動作しません。
また、すべてのスクリプトでトラップハンドラを試しましたが、script0.shでのみトラップハンドラを呼び出しました。
サブプロセス(例:script1.sh)を終了するためにscript0.shのトラップハンドラを試しましたが、プロセスが完了するまで停止します。
"trap -p"コマンドを使用してすべてのスクリプトに対してトラップハンドラを登録しましたが、script0.shにのみトラップハンドラがあることを確認しました。
メモ:
- script2.shは実際には「rsync」であり、残りのスクリプトは私のものです。
- script1.sh、script2.sh、およびscript3.shは、「&」演算子を使用してバックグラウンドに送信されます。
- バックグラウンドで送信された各プロセスに対して「待機」を実行します。
この問題を再現するスクリプトファイルを作成しました。
スクリプト0.sh:
#!/usr/bin/env bash
function cleanup_script0()
{
echo "SIGINT in script0.sh"
kill -s SIGINT $script1_pid
wait $script1_pid
}
trap cleanup_script0 SIGINT
./script1.sh &
script1_pid=$!
wait $script1_pid
スクリプト1.sh:
#!/usr/bin/env bash
function cleanup_script1()
{
echo "SIGINT in script1.sh"
kill -s SIGINT $script2_pid
wait $script2_pid
kill -s SIGINT $script3_pid
wait $script3_pid
}
trap cleanup_script1 SIGINT
rsync_file_to_copy="$( mktemp )"
dd if=/dev/urandom of="$rsync_file_to_copy" bs=1M count=1
rsync --timeout=5 --bwlimit=200 "$rsync_file_to_copy" "$( mktemp -d )/" &
script2_pid=$!
wait $script2_pid
echo "Finished script2.sh"
./script3.sh
script3_pid=$!
wait $script3_pid
echo "Finished script3.sh"
Script3.sh:
#!/usr/bin/env bash
function cleanup_script3()
{
echo "SIGINT in script3.sh"
}
trap cleanup_script3 SIGINT
delay_counter=0
while [ 8 -gt $delay_counter ]; do
echo "script3.sh: $( date "+%H_%M_%S" )"
let 'delay_counter++'
sleep 1
done
上記のスクリプトの実行結果は次のとおりです。
再同期中にCTRL + Cを押すと出力されます。
$ ./script0.sh
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00604244 s, 174 MB/s
^CSIGINT in script0.sh
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(703) [sender=3.2.3]
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at io.c(503) [generator=3.2.3]
Finished script2.sh
script3.sh: 23_57_24
script3.sh: 23_57_25
script3.sh: 23_57_26
script3.sh: 23_57_27
script3.sh: 23_57_28
script3.sh: 23_57_29
script3.sh: 23_57_30
script3.sh: 23_57_31
Finished script3.sh
script3.sh中にCTRL+Cを押すと出力されます。
$ ./script0.sh
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00585018 s, 179 MB/s
Finished script2.sh
script3.sh: 23_57_46
script3.sh: 23_57_47
^CSIGINT in script0.sh
script3.sh: 23_57_48
script3.sh: 23_57_49
script3.sh: 23_57_50
script3.sh: 23_57_51
script3.sh: 23_57_52
script3.sh: 23_57_53
Finished script3.sh
答え1
control+を選択するcと、SIGINTはフォアグラウンドプロセスグループのすべてのメンバーに送信されます(または信号はまったく送信されません。termios
マニュアルページを参照)。したがって、スクリプトが実際にますます多くのタスクを実行しても、プロセスグループに送信される信号の一般的な動作に応じて信号処理を簡素化できます。
#!/bin/sh
# script0 - apparently this script does more things that were absent
# in the question, so we run the first script instead of executing
# the next script (this changes nothing from the prior result)
./script1
echo and we do some other things here ...
そしてscript1
今、明らかにどこかで一種の出力リダイレクトが行われているので、これが上部で発生すると仮定しましょう(以前の結果と何も変わらない)。
#!/usr/bin/env bash
# script1 - replace rsync with a hopefully similar `sleep` call,
# plus now the output redirect, minus anything they haven't yet
# told us about
exec > >(tee and-a-ruthless-devotion-to-the-pope) 2>&1
echo RUN script2
# `command & wait;` is just a complicated and verbose way to write
# `command;` (unless there is yet another thing going on they
# haven't yet told us about??)
sleep 9
echo RUN script3
./script3
そしてscript3
#!/usr/bin/env bash
delay_counter=0
while [[ 8 -gt $delay_counter ]]; do
echo -n "script3 time "
date +%H:%M:%S
(( delay_counter++ ))
sleep 1
done
その後もchmod +x script*
引き続き原因
$ ./script0
RUN script2
^C
$ ./script0
RUN script2
RUN script3
script3 time 16:28:31
script3 time 16:28:32
script3 time 16:28:33
^C
$
不要な信号処理は状況を複雑にするだけであり、結果として生じる複雑さを解決するためにはより複雑さが必要です。基本的な動作を単純化し、それに依存しないのはなぜですか?