A solução super simples é adicionar isso no final do script:
kill -- -$$
Explicação:
$$
nos dá o PID do shell em execução. Então, kill $$
enviaria um SIGTERM para o processo de shell. No entanto, se negarmos o PID, kill
enviará um SIGTERM para cada processo no grupo de processos . Precisamos do --
antes, então kill
sabe que -$$
é um ID do grupo de processos e não um sinalizador.
Observe que isso depende do shell em execução ser líder do grupo de processos! Caso contrário, $$
(o PID) não corresponderá ao ID do grupo de processos e você enviará um sinal para quem sabe onde (bem, provavelmente em nenhum lugar, como é improvável que seja um grupo de processos com uma ID correspondente, se não formos um líder de grupo).
Quando o shell é iniciado, ele cria um novo grupo de processos [1]. Todo processo bifurcado torna-se um membro desse grupo de processos, a menos que eles alterem explicitamente seu grupo de processos por meio de um syscall ( setpgid
).
A maneira mais fácil de garantir um script específico é executada como um líder do grupo de processos, que é iniciado usando setsid
. Por exemplo, tenho alguns desses scripts de status que inicio a partir de um script pai:
#!/bin/sh
wifi_status &
bat_status &
Escrito assim, os scripts de Wi-Fi e bateria são executados com o mesmo grupo de processos que o script pai e kill -- -$$
não funciona. A correção é:
#!/bin/sh
setsid wifi_status &
setsid bat_status &
Eu achei pstree -p -g
útil para visualizar o processo & IDs de grupos de processos.
Obrigado a todos que contribuíram e me fizeram cavar um pouco mais, aprendi coisas! :)
[1] há outras circunstâncias em que o shell cria um grupo de processos? por exemplo. ao iniciar um subshell? eu não sei ...