バックグラウンドプロセスを1つのグループで起動し、後ですべてを強制終了する

バックグラウンドプロセスを1つのグループで起動し、後ですべてを強制終了する

先日、私はピッドと、そのすべての子プロセスについて考えましたが、しばらく時間を費やした後、私はそれが信頼できないと判断しました。なぜなら、子プロセスの一部がPPID1

今、私が探しているのは、次の関数をバックグラウンドで実行し、関数と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

(は、プロセス グループでコマンド ラインを実行してそれらを管理できるようにするシェルの動作 (フォアグラウンド/バックグラウンド/強制終了/サスペンド/再開) のためです) jjob control

以下について知ることができます仕事対話型シェルのjobsコマンドを実行します (ただし、シェル内のすべてのプロセスではありません)。 jobs -pプロセス グループ ID が表示されます。

-xプロセスグループIDが指定されたシグナルをプロセスグループに送信することで、プロセスグループのメンバーを強制終了できますxPGID) または を使用したジョブ仕様を使用します%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終了されなくなります。

関連情報