次のようなスクリプトがあるとします
#!/usr/bin/env zsh
./subscript.sh &
# do stuff
...
# do more stuff
subscript.sh
実行中のプロセス(およびそれによって開始されたすべてのプロセス) を、次の場合に完全に終了したいと思います。
- 上記のスクリプトは終了する
- 上記のスクリプトは何らかの理由で強制終了されます。
上記をどのように強制できますか? これはシェルによって自動的に処理されますか?
答え1
シェルは、サブプロセスを自発的に終了することは絶対にありません。結局のところ、バックグラウンドジョブはバックグラウンドで実行され、親の存続を気にする必要はないからです。(対話型シェルは、状況によっては終了時にサブプロセスを終了しますが、これは必ずしも望ましいことではありません。そのため、nohup
。
シェル スクリプトが終了したとき、またはキャッチ可能なシグナルによって強制終了されたときに、バックグラウンド ジョブを強制終了するように設定できます。ジョブのプロセス ID を記録し、トラップからジョブを強制終了します。これにより、ジョブ (つまり、バックグラウンドで開始された元のプロセス) のみが強制終了され、サブプロセスは強制終了されないことに注意してください。
jobs=()
trap '((#jobs == 0)) || kill $jobs' EXIT HUP TERM INT
…
subscript1 & jobs+=($!)
subscript2 & jobs+=($!)
…
すべてのプロセスとそのサブプロセスを確実に終了したい場合は、さらに計画を立てる必要があります。 1 つの方法は、すべてのプロセスが一意のファイルを開くようにすることです。 それらすべてを終了させるには、このファイルを開いているすべてのプロセスを終了します。 サブプロセスは、ファイルを閉じることで回避できます。
#!/bin/sh
lock_file=$(mktemp)
exec 3<"$lock_file"
your_script
status=$?
exec 3<&-
fuser -k "$lock_file"
exit $status
答え2
EXIT をトラップし、スクリプトのプロセス グループにシグナルを送信できます。
Linuxの場合
trap 'kill -SIGTERM 0' EXIT
FreeBSDで
trap 'kill -15 -$$' EXIT
SIGKILL
スクリプトが無条件に強制終了されるため、これが機能しない唯一のシグナルです。