シェルスクリプトからバックグラウンドプロセスを開始し、スクリプトが終了したらこのプロセスを強制終了したいと思います。
シェルスクリプトからこのプロセスのPIDを取得するにはどうすればよいですか?私が見る限り、変数$!
にはバックグラウンドプロセスではなく、現在のスクリプトのPIDが含まれています。
シェルスクリプトからバックグラウンドプロセスを開始し、スクリプトが終了したらこのプロセスを強制終了したいと思います。
シェルスクリプトからこのプロセスのPIDを取得するにはどうすればよいですか?私が見る限り、変数$!
にはバックグラウンドプロセスではなく、現在のスクリプトのPIDが含まれています。
回答:
開始時にバックグラウンドプロセスのPIDを保存する必要があります。
foo &
FOO_PID=$!
# do other stuff
kill $FOO_PID
ジョブ制御はインタラクティブな機能であり、制御端末に関連付けられているため、使用できません。スクリプトには必ずしもターミナルが接続されている必要はないため、ジョブ制御を利用できるとは限りません。
foo
と$!
、私たちは代わりにその何かのpidを取得するfoo
の?
foo
たまたま複数のパイプされたコマンド(たとえばtail -f somefile.txt | grep sometext
)である場合に役立ちます そのような場合、grepコマンドのPIDは、$!
それが探していたものであれば、tailコマンドではなくから取得します。この場合はjobs
またはps
などを使用する必要があります。
grep
ますが、それをkillすると、tailはパイプに書き込もうとしたときにSIGPIPEを取得します。しかし、トリッキーなプロセス管理/制御に取り掛かろうとすると、bash / shellは非常に苦痛になります。
/bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &
sysfault Nov 24 '10 at 14:28
jobs -l
コマンドを使用して、特定のジョブにアクセスできますL
^Z
[1]+ Stopped guard
my_mac:workspace r$ jobs -l
[1]+ 46841 Suspended: 18 guard
この場合、46841がPIDです。
からhelp jobs
:
-lジョブのプロセスグループIDと作業ディレクトリを報告します。
jobs -p
PIDのみを表示する別のオプションです。
$!
開始直後のPIDの保存は、ほとんどの場合、移植性が高く、簡単です。それが現在受け入れられている答えです。
jobs -p
jobs -l
Lubuntu 16.4 と同じ結果を返しました
bashスクリプトのすべての子プロセスを強制終了するさらに簡単な方法:
pkill -P $$
-P
フラグはと同じように動作pkill
し、pgrep
だけで、それは子プロセスを取得します- pkill
子プロセスが殺されるととpgrep
子のPID stdoutに出力されています。
bash -c 'bash -c "sleep 300 &"' &
実行後pgrep -P $$
は何も表示されません。これは、スリープがシェルの直接の子ではないためです。
$$
現在のシェルを参照するためです。
bash -c 'bash -c "sleep 300 &"' & ; pgrep -P $$
、私は標準出力に乗る[1] <pid>. So at least it shows something, but this is probably not the output of
pgrep`に参加します
bash -c 'bash -c "sleep 10 & wait $!"' & sleep 0.1; pstree -p $$
これは私がやったことです。それをチェックして、それが役に立てば幸いです。
#!/bin/bash
#
# So something to show.
echo "UNO" > UNO.txt
echo "DOS" > DOS.txt
#
# Initialize Pid List
dPidLst=""
#
# Generate background processes
tail -f UNO.txt&
dPidLst="$dPidLst $!"
tail -f DOS.txt&
dPidLst="$dPidLst $!"
#
# Report process IDs
echo PID=$$
echo dPidLst=$dPidLst
#
# Show process on current shell
ps -f
#
# Start killing background processes from list
for dPid in $dPidLst
do
echo killing $dPid. Process is still there.
ps | grep $dPid
kill $dPid
ps | grep $dPid
echo Just ran "'"ps"'" command, $dPid must not show again.
done
:そして、同じようにそれを実行./bgkill.sh
もちろんの適切な権限を持ちます
root@umsstd22 [P]:~# ./bgkill.sh
PID=23757
dPidLst= 23758 23759
UNO
DOS
UID PID PPID C STIME TTY TIME CMD
root 3937 3935 0 11:07 pts/5 00:00:00 -bash
root 23757 3937 0 11:55 pts/5 00:00:00 /bin/bash ./bgkill.sh
root 23758 23757 0 11:55 pts/5 00:00:00 tail -f UNO.txt
root 23759 23757 0 11:55 pts/5 00:00:00 tail -f DOS.txt
root 23760 23757 0 11:55 pts/5 00:00:00 ps -f
killing 23758. Process is still there.
23758 pts/5 00:00:00 tail
./bgkill.sh: line 24: 23758 Terminated tail -f UNO.txt
Just ran 'ps' command, 23758 must not show again.
killing 23759. Process is still there.
23759 pts/5 00:00:00 tail
./bgkill.sh: line 24: 23759 Terminated tail -f DOS.txt
Just ran 'ps' command, 23759 must not show again.
root@umsstd22 [P]:~# ps -f
UID PID PPID C STIME TTY TIME CMD
root 3937 3935 0 11:07 pts/5 00:00:00 -bash
root 24200 3937 0 11:56 pts/5 00:00:00 ps -f
pgrep
親プロセスのすべての子PIDを取得できます。前述のとおり$$
、現在のスクリプトのPIDです。したがって、後からクリーンアップするスクリプトが必要な場合は、これでうまくいきます。
trap 'kill $( pgrep -P $$ | tr "\n" " " )' SIGINT SIGTERM EXIT
trap 'pkill -P $$' SIGING SIGTERM EXIT
シンプルに見えますが、テストしていません。
SIG
プレフィックスを使用しないでください。これはPOSIXで許可されていますが、実装がサポートする可能性のある拡張機能として次のとおりです。