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:
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.