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