Запустить фоновые процессы в одной группе, а затем завершить их все

Запустить фоновые процессы в одной группе, а затем завершить их все

На днях я попытался написать сценарий, который убил быПИДи все его дочерние процессы, но потратив на это некоторое время, я решил, что это не заслуживает доверия, потому что иногда некоторые из дочерних процессов заканчивалисьППИДиз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, но я включил ее сюда, потому что это функция, которую я использую много раз в этом скрипте. Кроме того, я даю максимальный лимит времени300curl, но в зависимости от некоторых сетевых ошибок он также зависает .

решение1

Обычно, если вы вызываете свой скрипт из интерактивной оболочки, он помещается в новую группу процессов (также известную как job), поэтому если вы Ctrl-Cв ней, все процессы, запущенные этим скриптом, получат сигнал SIGINT.

Если вы запустили его в фоновом режиме (все еще из интерактивной оболочки), он также будет запущен в своей собственной группе процессов.

Информацию о группах процессов можно получить с помощью:

ps -j

( jдля job controlчего предназначено поведение оболочек, которые запускают командные строки в группах процессов, чтобы иметь возможность управлять ими (передний план/фоновый режим/завершение/приостановка/возобновление)).

Вы можете узнать орабочие меставашей интерактивной оболочки с помощью jobsкоманды (хотя и не всех процессов в ней). jobs -pпокажет вам идентификатор группы процессов.

Вы можете уничтожить участников группы процессов, отправив сигнал туда, -xгде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он не будет убит.

Связанный контент