Como posso matar e esperar por processos em segundo plano para terminar em um script de shell quando eu Ctrl + C é?

3

Estou tentando configurar um script de shell para que ele execute processos em segundo plano, e quando eu ctrl + C o script de shell, ele mata os filhos e sai.

O melhor que eu consegui fazer é isso. Parece que kill 0 -INT também mata o script antes que a espera aconteça, portanto, o script de shell morre antes que as crianças sejam concluídas.

Alguma idéia de como eu posso fazer este script de shell esperar que as crianças morram depois de enviar o INT?

#!/bin/bash
trap 'killall' INT

killall() {
    echo **** Shutting down... ****
    kill 0 -INT
    wait # Why doesn't this wait??
    echo DONE
}

process1 &
process2 &
process3 &

cat # wait forever
    
por slipheed 13.11.2012 / 03:30

2 respostas

2

Primeiro, você deve saber que kill 0 envia o sinal para todo o processo no grupo de processos atual. (veja kill (1) - man page do Linux ) Meu palpite é que está matando mais do que deveria. É por isso que wait não está esperando, está sendo terminado por algum motivo. Minha melhor aposta para resolver este problema é fazer uma iteração sobre a execução de jobs a partir de jobs -pr , matando um por um: dessa forma eu garanto que o sinal é enviado apenas para processos filhos naquele momento e nada mais.

Para fazer isso funcionar, fiz vários testes, mas não consegui enviar o SIGINT para processos filhos. Eles simples não reagem a isso! Pesquisando na Web, encontrei esta resposta no Stack Overflow:

link

Portanto, o verdadeiro problema é que você não pode enviar o SIGINT de um script para outro , porque em shells não interativos o sinal é ignorado. Não consegui resolver esse problema (usar bash -i para chamar o script filho não funciona).

Eu sei que você provavelmente quer enviar o SIGINT e esperar que os processos filhos sejam desligados normalmente, mas se você não se importar em usar o SIGTERM (ou qualquer outro sinal além do SIGINT) este é o melhor script que escrevi:

#!/bin/bash
trap 'killall' INT

killall() {
    echo '**** Shutting down... ****'
    jobs -pr
    for i in $(jobs -pr); do
        kill -TERM $i
    done
    wait
    echo DONE
}

./long.sh &
./long.sh &
./long.sh &

cat # wait forever

Para testar, criei este script long.sh :

#!/bin/bash
trap 'killall' TERM

echo "Started... $$" >> file.txt

killall() {
    # shutting down gracefully
    echo "Finished... $$" >> file.txt
    exit # don't forget this!
}

# infinite loop
while true; do echo loop >/dev/null ; done

Neste último script, não usei a função sleep porque ela cria um novo processo que permanece na memória mesmo depois que o script é concluído. Em seu script, você pode chamar novos processos, mas deve assegurar a transmissão do SIGTERM (ou qualquer outro sinal que você tenha usado) para todos eles.

    
por 20.06.2013 / 18:12
0

Isso parece funcionar. Certifique-se de usar "/ usr / bin / kill" e não o "kill" interno do Bash.

[myles@marklar ~]$ /usr/bin/kill --version
kill from util-linux-2.13-pre7

Observe que o controle de tarefas não está ativado em shells Bash não interativos (por exemplo, scripts).

#!/bin/bash

trap kill_jobs 2

kill_jobs()
{
        while /usr/bin/kill 0; do :; done
        exit 0
}

foo &
foo &
foo &

sleep 777777
    
por 13.11.2012 / 05:23