Lidando com a hierarquia do processo

Pegue este script bash simples e burro que apenas inicia dois subprocessos (um em segundo plano, o outro esperando):

#!/bin/bash
sleep
40 & sleep 41

Execute, aqui está a árvore do processo:

  PID  PGID STAT CMD
8709 8709 Ss /bin/zsh
14431 14431 S+ \_ sh ./runsubprocess
14432 14431 S+ \_ sleep 40
14433 14431 S+ \_ sleep 41

Em seguida, mate-o com kill 14431, aqui está a árvore do processo:

  PID  PGID STAT CMD
14432 14431 S sleep 40
14433 14431 S sleep 41

Deixamos dois processos em execução 🙁

Solução: use pkill para matar as crianças também!

Mate-o pkill -P 14431e agora você não terá mais órfãos.

Cenário

pkill matará o processo e seus filhos, não os netos!

Imagine que você tem este script:

#!/bin/bash
(sleep 40 & sleep 41) & sleep 42

Árvore de processos:

  PID  PGID STAT CMD
8709 8709 Ss /bin/zsh
14431 14431 S+ \_ sh ./runsubprocess
14432 14431 S+ \_ sleep 41
14434 14431 S+ | \_ sleep 40
14433 14431 S+ \_ sleep 42

Usando pkill -P 14431você ainda deixa este processo para trás:

  PID  PGID STAT CMD
14434 14431 S sleep 40

Foda-se! Mas aí vem o PGID (Id do Grupo de Processo). Observe como todo processo originalmente iniciado pelo mesmo ancestral tem o mesmo PGID (aqui 14431). Funciona assim, define os subprocessos e sua raiz original. O processo raiz geralmente tem PID = PGID. E, oh, matar pode matar por PGID se prefixar com uma pitada: .kill -TERM -$PGID

Usar é a maneira melhor e mais fácil de alcançar o que procurávamos.kill -TERM -14431

Notas adicionais:
→ Eu costumava ps fo pid,pgid,stat,cmdmostrar as árvores de processo da maneira como são coladas aqui 🙂
→ Os processos mantêm seu PGID original, mesmo que o ancestral tenha morrido. Você ainda pode matar por PGID se você esqueceu alguns órfãos.
→ Suponho que você possa enfrentar exceções, então se o processo root for PID ≠ PGID, você ainda pode obter o PGID do PID:echo $PID |xargs echo | xargs -i ps -o pgid -p {}|xargs echo |awk '{print $2}'