次のようなBashスクリプトがある場合:
function repeat {
while :; do
echo repeating; sleep 1
done
}
repeat &
echo running once
running once
一度印刷されますが、repeat
フォークは永遠に存在し、無限に印刷されます。
repeat
これを生成したスクリプトが終了した後も引き続き実行されないようにするにはどうすればよいですか?
bash -c
新しいインタプリタを明示的にインスタンス化すると、親プロセスが消えたため強制的に終了すると思われましたが、孤児プロセスはinit
PID 1によって採用されているようです。
別のファイルでこれをテストしてください。
# repeat.bash
while :; do echo repeating; sleep 1; done
# fork.bash
bash -c "./repeat.bash & echo an exiting command"
実行すると、バックグラウンドで実行され./fork.bash
続けます。repeat.bash
簡単で怠惰な解決策は、次の行を追加することですfork.bash
。
pkill repeat.bash
ただし、他の重要なプロセスではこの名前を使用しないことをお勧めします。それ以外の場合は名前も消去されます。
バックグラウンドジョブを生成したスクリプト(またはプロセス)が終了したときに終了する必要がある分岐シェルで、バックグラウンドジョブを処理するためのより優れた許容可能な方法があるかどうか疑問に思います。
すべてのプロセスで同じ名前を盲目的に使用するよりも良い方法がない場合は、
pkilling
ネットワークサーバーと同じように実行されている冗長タスクを処理して終了する必要がありますか?cron
スクリプトがgit
リポジトリにあり、コードを変更せずに自分で含める必要があるため、作業を避けたいと思います/etc/
。
ベストアンサー1
スクリプトが終了する前にバックグラウンドプロセスが終了します。
trap '[ "$pid" ] && kill "$pid"' EXIT
function repeat {
while :; do
echo repeating; sleep 1
done
}
repeat &
pid=$!
echo running once
どのように動作しますか?
trap '[ "$pid" ] && kill "$pid"' EXIT
これは罠。スクリプトが終了しようとするたびに、単一引用符で囲まれたコマンドが実行されます。このコマンドは、シェル変数にNULL以外の
pid
値が指定されていることを確認します。存在する場合、そのプロセスに関連するプロセスはpid
終了します。pid=$!
これにより、前のバックグラウンドcommand()のプロセスIDが
repeat &
シェル変数に保存されますpid
。
改善する
〜のようにパトリックコメントで指摘したように、スクリプトが終了する可能性があります。後ろにバックグラウンドプロセスが開始されますが、今後変数がpid
設定されました。次のコードを使用してこの状況を処理できます。
my_exit() {
[ "$racing" ] && pid=$!
[ "$pid" ] && kill "$pid"
}
trap my_exit EXIT
function repeat {
while :; do
echo repeating; sleep 1
done
}
racing=Y
repeat &
pid=$!
racing=
echo running once