すべての例はbashで記述されていますが、(最小限の変更で)kshで機能します。Cshにはバックグラウンドのプロセス管理機能もあるため、同様のアプローチを使用できます。
仕事の管理
これは、manを読むのが好きな場合に備えて、詳細が説明されているmanbashのセクションの名前です。次の簡単な機能を使用します。command
& -バックグラウンド
ジョブでコマンドを実行します-バックグラウンドコマンドのリストを出力します
有用なアクションを実行しない簡単な例。test.txtファイルから数値が読み取られ、3つのプロセスが並行して起動され、対応する秒数の間スリープします。3秒ごとに、実行中のプロセスの数がチェックされ、3つ未満の場合は、新しいプロセスが開始されます。バックグラウンドプロセスの起動は別の関数mytaskに移動されましたが、ループで直接開始できます。
test.sh
#!/bin/bash
NJOBS=3 ; export NJOBS
function mytask () {
echo sleeping for $1
sleep $1
}
for i in $( cat test.txt )
do
while [ $(jobs | wc -l ) -ge $NJOBS ]
do
sleep 3
done
echo executing task for $i
mytask $i &
done
echo waiting for $( jobs | wc -l ) jobs to complete
wait
入力データ:
test.txt
60
50
30
21
12
13
50
30
21
12
13
ループ後の待機に注意してください。コマンドは、バックグラウンドで実行されているプロセスが終了するのを待機しています。これがないと、スクリプトはループの終了直後に終了し、すべてのバックグラウンドプロセスが中断されます。おそらく、この待機は有名なミーム「ああ、待って!!!」で言及されています。
バックグラウンドプロセスの終了
Ctrl-Cでスクリプトを中断すると、すべてのバックグラウンドプロセスでスクリプトが強制終了されます。端末で実行されているすべてのプロセスは、キーボードから信号を受信します(たとえば、SIGINT)。スクリプトがkillコマンドを使用して別の端末から強制終了された場合、バックグラウンドプロセスは終了するまで実行されたままになるため、これを覚えておく必要があります。
スポイラーヘッダー
user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»
user 1363 775 0 12:31 pts/5 00:00:00 ./test.sh
user 1368 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1387 1363 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3
user 1389 556 0 12:31 pts/2 00:00:00 grep --colour=auto -E test|sleep
user@somehost ~/tmp2 $ kill 1363
user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»
user 1368 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1399 556 0 12:32 pts/2 00:00:00 grep --colour=auto -E test|sleep
user 1363 775 0 12:31 pts/5 00:00:00 ./test.sh
user 1368 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1387 1363 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3
user 1389 556 0 12:31 pts/2 00:00:00 grep --colour=auto -E test|sleep
user@somehost ~/tmp2 $ kill 1363
user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»
user 1368 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1399 556 0 12:32 pts/2 00:00:00 grep --colour=auto -E test|sleep
この状況は、必要な信号をインターセプトすることで処理できます。スクリプトの先頭にハンドラーを追加します。
トラップ
function pids_recursive() {
cpids=`pgrep -P $1|xargs`
echo $cpids
for cpid in $cpids;
do
pids_recursive $cpid
done
}
function kill_me () {
kill -9 $( pids_recursive $$ | xargs )
exit 1
}
#
#trap 'echo trap SIGINT; kill_me ' SIGINT
trap 'echo trap SIGTERM; kill_me' SIGTERM
kill -Lは、既存の信号のリストを表示します。必要に応じて、必要な信号のハンドラーを追加できます。