web-dev-qa-db-ja.com

複数のプログラムを実行してクローズを処理するBash

複数のプログラムを実行するbashスクリプトがあります

#!/bin/sh
python program1.py &
python program2.py &
other programs ... &
lastProgram

./myscript.shとして実行します

Ctl-Cを押してlastProgramを閉じると、終了し、他のすべてのものはバックグラウンドで実行され続けます。問題は、他のプログラムを終了する必要があることです。

スクリプトから開始されたすべてのプログラムの終了を処理する適切な方法はどれですか。

4
Ricard Molins

プロセスIDを収集し、終了時にバックグラウンドプロセスを強制終了します。

#!/bin/bash
killbg() {
        for p in "${pids[@]}" ; do
                kill "$p";
        done
}
trap killbg EXIT
pids=()
background job 1 & 
pids+=($!)
background job 2... & 
pids+=($!)
foreground job

トラップEXITは、理由に関係なく、シェルの終了時に関数を実行します。これをtrap killbg SIGINTに変更して、^Cでのみ実行できます。

これは、スクリプトがそれらを撮影しようとする前にバックグラウンドプロセスの1つが終了したかどうかをチェックしません。そうした場合、エラーが発生したり、さらに悪いことに、間違ったプロセスを実行したりする可能性があります。


または、ジョブIDで殺します。 jobsの出力を読んで、まだアクティブなものを見つけましょう。

#!/bin/bash 
killjobs() {
    for x in $(jobs | awk -F '[][]' '{print $2}' ) ; do 
        kill %$x
    done
}
trap killjobs EXIT
sleep 999 &
sleep 1 &
sleep 999 &
sleep 30

他のプロセスを生成するバックグラウンドプロセス(サブシェル:(sleep 1234 ; echo foo) &)を実行する場合、これを機能させるには、set -m(「モニターモード」)を使用してジョブ制御を有効にする必要があります。それ以外の場合は、リードプロセスのみが終了します。

4
ilkkachu

私はPIDの収集について同様の質問を読んでいて、スクリプトの最後にそれらをすべて殺していました-問題は、完了したプロセスのPIDです- リサイクルして新しいプロセスで再利用できますスクリプトが終了する前に、次のことができます新しい(ランダム)プロセスを強制終了します

EXITをトラップし、bashのジョブ制御で殺す

Bashのジョブ制御を使用して、トラップと%n jobspecを使用してスクリプトで開始されたプロセスのみを強制終了し、実行可能なジョブの最大数をカウントできます(この例では3つのみ)。

#!/bin/bash
#trap 'kill %1 %2 %3' 0     # 0 or EXIT are equivalent
#trap 'kill %1 %2 %3' EXIT  # or use {1..n} as below
trap 'kill %{1..3}' EXIT
sleep 33 &
sleep 33 &
sleep 33 &
echo processes are running, ctrl-c the next sleep
sleep 66
echo this line will never be executed

すでに終了している存在しないjobspecに対する追加の「キル」は、エラーメッセージのみを発生させ、他の新しい/ランダムプロセスを強制終了しません。


スクリプトの完全なプロセスグループを終了する

ここでは、スクリプトの完全なプロセスグループを強制終了する方法が少し異なります。しかし、スクリプト/シェルのジョブ制御が設定されていない場合、それはcould親からPPIDを継承します...しかし、ジョブ制御なしでは、上記も機能しません。

違いは、新しいプロセスのPGIDになるため、bashのPIDを使用するトラップのこのkillコマンドです。

trap 'kill -- -$$' EXIT

this related Q または ここで、Johannes 'fish' ZiemkeがSIGINTおよびSIGTERMをトラップし、setsidを使用して "新しいプロセスでプロセスグループ全体をkillします私たち自身を殺すリスクを負わないようにグループ化します。 "

3
Xen2050

lastProgramの実行が完了する前に完了しないバックグラウンドプロセスをすべて強制終了するには、すべてのPIDを保存する必要があります。

python program1.py &
p1pid=$!
python program2.py &
p2pid=$!
other programs ... &
p3pid=$!
lastProgram

kill $p1pid $p2pid $p3pid

スクリプトを終了する前に、すべてのバックグラウンドプロセスの実行が完了するまで待機するだけの場合は、waitコマンドを使用できます。

python program1.py &
python program2.py &
other programs ... &
lastProgram
wait
1
jordanm