Lança os processos em segundo plano em um grupo e depois os mata todos

5

Outro dia eu tentei escrever um script que mataria um PID e todos os seus processos filhos, mas depois de passar algum tempo nisso, eu decidi que não era confiável, porque às vezes alguns dos as crianças acabariam com um PPID de 1 .

Agora, o que estou procurando é como executar a seguinte função em segundo plano e ter a função e curl all no mesmo group e depois matar esse script se fica preso, matando todos os seus filhos que ficaram em segundo plano:

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

Eu sei que não há necessidade para esta função download , mas eu incluí aqui porque é uma função que eu uso muitas vezes neste script. Além disso, estou dando um limite máximo de tempo de 300 para curl , mas, dependendo de alguns erros de rede, ele também fica preso.

    
por Teresa e Junior 25.06.2014 / 13:29

1 resposta

5

Normalmente, se você invocar seu script a partir de um shell interativo, ele será colocado em um novo grupo de processos (também conhecido como job ), então se você Ctrl-C nele, todo o os processos iniciados por esse script receberão um SIGINT.

Se você começou em segundo plano também (ainda de um shell interativo), ele também será iniciado em seu próprio grupo de processos.

Você pode descobrir sobre grupos de processos com:

ps -j

( j é para job control , que é o comportamento de shells que executam linhas de comando em grupos de processos para poder gerenciá-los (foreground / background / kill / suspend / resume)).

Você pode descobrir sobre os jobs do seu shell interativo com o comando jobs (embora nem todos os processos nele contidos). jobs -p mostrará o ID do grupo de processos.

Você pode matar os membros de um grupo de processos enviando um sinal para -x , em que x é o ID do grupo de processos ( PGID ) ou usando especificações de trabalhos com %job-number . Por exemplo:

$ 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

Agora, se não iniciado a partir de um shell interativo, seu script será finalizado no mesmo grupo de processos que seu pai. Então matar esse grupo de processos pode acabar matando um monte de outros processos que você não quer matar.

O que você poderia fazer no seu script é iniciar o grupo de processos você mesmo.

Como adicionando:

[ "$(ps -o pgid= -p "$$")" -eq "$$" ] ||
  exec perl -e 'setpgrp or die "setpgrp; $!"; exec @ARGV' -- "$0" "$@"

(que reexecuta o script depois de ter chamado perl para iniciar um novo grupo de processos se detectarmos que não somos líderes de grupos de processos) no início do seu script.

Dessa forma, você tem a garantia de que o script será executado em seu próprio grupo de processos.

O que isso significa é que, se você fizer isso:

something | myscript | something

em um shell interativo, as chances são de myscript não ser o líder do grupo de processos. Ao fazer o setpgrp acima, o script não estará mais no grupo de processos em primeiro plano do terminal, o que significa que Ctrl-C não o matará.

    
por 26.06.2014 / 23:52

Tags