Seu comando kill está invertido.
Como muitos comandos do UNIX, as opções que começam com menos devem vir primeiro, antes de outros argumentos.
Se você escrever
kill -INT 0
ele vê o -INT como uma opção e envia SIGINT para 0 ( 0 é um número especial que significa todos os processos no grupo de processos atual).
Mas se você escrever
kill 0 -INT
ele vê o 0 , decide que não há mais opções, então usa SIGTERM por padrão. E envia isso para o grupo de processos atual, o mesmo que se você fizesse
kill -TERM 0 -INT
(também tentaria enviar SIGTERM para -INT , o que causaria um erro de sintaxe, mas envia SIGTERM para 0 primeiro e nunca chega tão longe.)
Portanto, seu script principal está recebendo um SIGTERM antes de executar os wait e echo DONE .
Adicionar
trap 'echo got SIGTERM' TERM
no topo, logo após
trap 'killall' INT
e execute-o novamente para provar isso.
Como Stephane Chazelas aponta, seus filhos de segundo plano ( process1 , etc.) irão ignorar SIGINT por padrão.
De qualquer forma, acho que enviar SIGTERM faria mais sentido.
Finalmente, não tenho certeza se kill -process group tem a garantia de ir primeiro aos filhos. Ignorar sinais durante o desligamento pode ser uma boa ideia.
Então tente isto:
#!/bin/bash
trap 'killall' INT
killall() {
trap '' INT TERM # ignore INT and TERM while shutting down
echo "**** Shutting down... ****" # added double quotes
kill -TERM 0 # fixed order, send TERM not INT
wait
echo DONE
}
./process1 &
./process2 &
./process3 &
cat # wait forever