GNU/Linux >> Linux Esercitazione >  >> Linux

Qual è il modo migliore per inviare un segnale a tutti i membri di un gruppo di processi?

Non dici se l'albero che vuoi uccidere è un singolo gruppo di processi. (Questo è spesso il caso se l'albero è il risultato di un fork dall'avvio di un server o da una riga di comando della shell.) Puoi scoprire i gruppi di processi usando GNU ps come segue:

 ps x -o  "%p %r %y %x %c "

Se si tratta di un gruppo di processi che si desidera terminare, utilizzare semplicemente kill(1) comando ma invece di assegnargli un numero di processo, assegnagli la negazione del numero del gruppo. Ad esempio, per terminare ogni processo nel gruppo 5112, usa kill -TERM -- -5112 .


Elimina tutti i processi appartenenti allo stesso albero dei processi utilizzando l'ID gruppo di processi (PGID )

  • kill -- -$PGID Usa segnale predefinito (TERM =15)
  • kill -9 -$PGID Usa il segnale KILL (9)

Puoi recuperare il PGID da qualsiasi ID processo (PID ) dello stesso albero dei processi

  • kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*') (segnale TERM )
  • kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*') (segnale KILL )

Spiegazione

  • kill -9 -"$PGID" => Invia segnale 9 (KILL ) a tutti i figli e nipoti...
  • PGID=$(ps opgid= "$PID") => Recupera l'Process-Group-ID da qualsiasi ID processo dell'albero, non solo il Process-Parent-ID . Una variazione di ps opgid= $PID è ps -o pgid --no-headers $PID dove pgid può essere sostituito da pgrp .
    Ma:
    • ps inserisce spazi iniziali quando PID è inferiore a cinque cifre e allineato a destra come notato da tanager. Puoi usare:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps da OSX stampa sempre l'intestazione, quindi Speakus propone:
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • grep -o [0-9]* stampa solo cifre successive (non stampa spazi o intestazioni alfabetiche).

Altre righe di comando

PGID=$(ps -o pgid= $PID | grep -o [0-9]*)
kill -TERM -"$PGID"  # kill -15
kill -INT  -"$PGID"  # correspond to [CRTL+C] from keyboard
kill -QUIT -"$PGID"  # correspond to [CRTL+\] from keyboard
kill -CONT -"$PGID"  # restart a stopped process (above signals do not kill it)
sleep 2              # wait terminate process (more time if required)
kill -KILL -"$PGID"  # kill -9 if it does not intercept signals (or buggy)

Limitazione

  • Come notato da davide e Hubert Kario, quando kill viene invocato da un processo appartenente allo stesso albero, kill rischia di uccidersi prima di terminare l'intero albero uccidendo.
  • Pertanto, assicurati di eseguire il comando utilizzando un processo con un Process-Group-ID diverso .

Lunga storia

> cat run-many-processes.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
./child.sh background &
./child.sh foreground
echo "ProcessID=$$ ends ($0)"

> cat child.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
./grandchild.sh background &
./grandchild.sh foreground
echo "ProcessID=$$ ends ($0)"

> cat grandchild.sh
#!/bin/sh
echo "ProcessID=$$ begins ($0)"
sleep 9999
echo "ProcessID=$$ ends ($0)"

Esegui l'albero dei processi in background usando '&'

> ./run-many-processes.sh &    
ProcessID=28957 begins (./run-many-processes.sh)
ProcessID=28959 begins (./child.sh)
ProcessID=28958 begins (./child.sh)
ProcessID=28960 begins (./grandchild.sh)
ProcessID=28961 begins (./grandchild.sh)
ProcessID=28962 begins (./grandchild.sh)
ProcessID=28963 begins (./grandchild.sh)

> PID=$!                    # get the Parent Process ID
> PGID=$(ps opgid= "$PID")  # get the Process Group ID

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    28969 Ss   33021   0:00 -bash
28349 28957 28957 28349 pts/3    28969 S    33021   0:00  \_ /bin/sh ./run-many-processes.sh
28957 28958 28957 28349 pts/3    28969 S    33021   0:00  |   \_ /bin/sh ./child.sh background
28958 28961 28957 28349 pts/3    28969 S    33021   0:00  |   |   \_ /bin/sh ./grandchild.sh background
28961 28965 28957 28349 pts/3    28969 S    33021   0:00  |   |   |   \_ sleep 9999
28958 28963 28957 28349 pts/3    28969 S    33021   0:00  |   |   \_ /bin/sh ./grandchild.sh foreground
28963 28967 28957 28349 pts/3    28969 S    33021   0:00  |   |       \_ sleep 9999
28957 28959 28957 28349 pts/3    28969 S    33021   0:00  |   \_ /bin/sh ./child.sh foreground
28959 28960 28957 28349 pts/3    28969 S    33021   0:00  |       \_ /bin/sh ./grandchild.sh background
28960 28964 28957 28349 pts/3    28969 S    33021   0:00  |       |   \_ sleep 9999
28959 28962 28957 28349 pts/3    28969 S    33021   0:00  |       \_ /bin/sh ./grandchild.sh foreground
28962 28966 28957 28349 pts/3    28969 S    33021   0:00  |           \_ sleep 9999
28349 28969 28969 28349 pts/3    28969 R+   33021   0:00  \_ ps fj

Il comando pkill -P $PID non uccide il nipote:

> pkill -P "$PID"
./run-many-processes.sh: line 4: 28958 Terminated              ./child.sh background
./run-many-processes.sh: line 4: 28959 Terminated              ./child.sh foreground
ProcessID=28957 ends (./run-many-processes.sh)
[1]+  Done                    ./run-many-processes.sh

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    28987 Ss   33021   0:00 -bash
28349 28987 28987 28349 pts/3    28987 R+   33021   0:00  \_ ps fj
    1 28963 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh foreground
28963 28967 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28962 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh foreground
28962 28966 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28961 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh background
28961 28965 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999
    1 28960 28957 28349 pts/3    28987 S    33021   0:00 /bin/sh ./grandchild.sh background
28960 28964 28957 28349 pts/3    28987 S    33021   0:00  \_ sleep 9999

Il comando kill -- -$PGID uccide tutti i processi incluso il nipote.

> kill --    -"$PGID"  # default signal is TERM (kill -15)
> kill -CONT -"$PGID"  # awake stopped processes
> kill -KILL -"$PGID"  # kill -9 to be sure

> ps fj
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
28348 28349 28349 28349 pts/3    29039 Ss   33021   0:00 -bash
28349 29039 29039 28349 pts/3    29039 R+   33021   0:00  \_ ps fj

Conclusione

Noto in questo esempio PID e PGID sono uguali (28957 ).
Questo è il motivo per cui inizialmente pensavo kill -- -$PID era abbastanza. Ma nel caso in cui il processo venga generato all'interno di un Makefile l'ID processo è diverso dall'ID gruppo .

Penso kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) è il trucco più semplice per terminare un intero albero di processi quando viene chiamato da un ID gruppo diverso (un altro albero dei processi).


pkill -TERM -P 27888

Questo terminerà tutti i processi che hanno l'ID processo genitore 27888.

O più robusto:

CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS

che pianifica l'uccisione 33 secondi dopo e chiede cortesemente ai processi di terminare.

Vedi questa risposta per terminare tutti i discendenti.


Linux
  1. Ho appena cancellato /bin. Qual è il modo migliore per recuperare?

  2. Qual è la differenza tra kill , pkill e killall?

  3. Qual è il modo più veloce per rimuovere tutti i file e le sottocartelle in una directory?

  4. Qual è il modo migliore per verificare se un volume è montato in uno script Bash?

  5. Qual è il modo migliore per ottenere informazioni sulle unità attualmente non montate?

Come elencare i membri di un gruppo in Linux

SIGTERM vs SIGKILL:qual è la differenza?

Qual è il comando kill in Linux?

Cos'è un processo interrotto in Linux?

Qual è il modo migliore per impostare una variabile d'ambiente in .bashrc?

Qual è il modo migliore per gestire le autorizzazioni per i dati www dell'utente di Apache 2 in /var/www?