
先日、私はピッドと、そのすべての子プロセスについて考えましたが、しばらく時間を費やした後、私はそれが信頼できないと判断しました。なぜなら、子プロセスの一部がPPIDの1。
今、私が探しているのは、次の関数をバックグラウンドで実行し、関数とcurl
すべてを同じにする方法ですグループそして、このスクリプトがスタックした場合には、バックグラウンドに残っているすべての子を強制終了します。
download(){
until curl -s -S -L -A Mozilla/5.0 -m 300 "$@"; do
echo Retrying in 5 seconds... >&2
sleep 5
done
}
for url in foo.com bar.com baz.com; do
download $url >$url &
done
wait
この関数は必要ないのは分かっていますdownload
が、このスクリプトでは何度も使用する関数なのでここに含めました。また、最大時間制限を設定しています。300ですcurl
が、ネットワーク エラーによっては停止してしまうこともあります。
答え1
job
通常、対話型シェルからスクリプトを呼び出すと、スクリプトは新しいプロセス グループ (別名)に配置されます。そのためCtrl-C、そのスクリプトによって開始されたすべてのプロセスは SIGINT を受け取ります。
バックグラウンドでも(対話型シェルから)起動した場合、独自のプロセス グループでも起動されます。
プロセス グループについては、次の方法で確認できます。
ps -j
(は、プロセス グループでコマンド ラインを実行してそれらを管理できるようにするシェルの動作 (フォアグラウンド/バックグラウンド/強制終了/サスペンド/再開) のためです) j
。job control
以下について知ることができます仕事対話型シェルのjobs
コマンドを実行します (ただし、シェル内のすべてのプロセスではありません)。 jobs -p
プロセス グループ ID が表示されます。
-x
プロセスグループIDが指定されたシグナルをプロセスグループに送信することで、プロセスグループのメンバーを強制終了できますx
(PGID) または を使用したジョブ仕様を使用します%job-number
。例:
$ sleep 30 | sleep 40 &
[1] 6950 6951
$ ps -j
PID PGID SID TTY TIME CMD
6031 6031 6031 pts/3 00:00:00 zsh
6950 6950 6031 pts/3 00:00:00 sleep
6951 6950 6031 pts/3 00:00:00 sleep
6952 6952 6031 pts/3 00:00:00 ps
$ kill -- -6950
[1] + terminated sleep 30 | sleep 40
$ sleep 30 | sleep 40 &
[1] 6955 6957
$ jobs
[1] + running sleep 30 | sleep 40
$ kill %1
[1] + terminated sleep 30 | sleep 40
ここで、対話型シェルから開始されていない場合、スクリプトは親と同じプロセス グループに含まれます。そのため、そのプロセス グループを強制終了すると、強制終了したくない他のプロセスも強制終了してしまう可能性があります。
スクリプトで実行できることは、プロセス グループを自分で開始することです。
追加して「いいね!」
[ "$(ps -o pgid= -p "$$")" -eq "$$" ] ||
exec perl -e 'setpgrp or die "setpgrp; $!"; exec @ARGV' -- "$0" "$@"
(プロセス グループ リーダーではないことが検出された場合は、新しいプロセス グループを開始するために呼び出した後、スクリプトを再実行しますperl
) をスクリプトの先頭に追加します。
こうすることで、スクリプトが独自のプロセス グループ内で実行されることが保証されます。
しかし、それは次のことを意味します:
something | myscript | something
対話型シェルでは、myscript
プロセス グループ リーダーにならない可能性があります。上記を実行するとsetpgrp
、スクリプトはターミナルのフォアグラウンド プロセス グループに存在しなくなり、強制Ctrl-C終了されなくなります。