GNU/Linux >> Tutoriels Linux >  >> Linux

Quelle est la meilleure façon d'envoyer un signal à tous les membres d'un groupe de processus ?

Vous ne dites pas si l'arbre que vous voulez tuer est un groupe de processus unique. (C'est souvent le cas si l'arborescence est le résultat d'un fork à partir d'un démarrage de serveur ou d'une ligne de commande shell.) Vous pouvez découvrir des groupes de processus à l'aide de GNU ps comme suit :

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

S'il s'agit d'un groupe de processus que vous voulez tuer, utilisez simplement le kill(1) commande mais au lieu de lui donner un numéro de processus, donnez-lui la négation du numéro de groupe. Par exemple, pour tuer tous les processus du groupe 5112, utilisez kill -TERM -- -5112 .


Tuez tous les processus appartenant au même arbre de processus en utilisant l'ID de groupe de processus (PGID )

  • kill -- -$PGID Utiliser le signal par défaut (TERM =15)
  • kill -9 -$PGID Utilisez le signal KILL (9)

Vous pouvez récupérer le PGID à partir de n'importe quel Process-ID (PID ) du même arbre de processus

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

Explication

  • kill -9 -"$PGID" => Envoyer le signal 9 (KILL ) à tous les enfants et petits-enfants...
  • PGID=$(ps opgid= "$PID") => Récupérer le Process-Group-ID à partir de n'importe quel Process-ID de l'arborescence, pas seulement le Process-Parent-ID . Une variation de ps opgid= $PID est ps -o pgid --no-headers $PID pgid peut être remplacé par pgrp .
    Mais :
    • ps insère des espaces à gauche lorsque PID est inférieur à cinq chiffres et aligné à droite, comme l'a remarqué Tangara. Vous pouvez utiliser:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps depuis OSX imprime toujours l'en-tête, donc Speakus propose :
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • grep -o [0-9]* imprime uniquement les chiffres successifs (n'imprime pas les espaces ou les en-têtes alphabétiques).

Autres lignes de commande

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)

Limites

  • Comme l'ont remarqué davide et Hubert Kario, lorsque kill est invoqué par un processus appartenant au même arbre, kill risque de se tuer avant de mettre fin à la destruction de l'arbre entier.
  • Par conséquent, assurez-vous d'exécuter la commande en utilisant un processus ayant un Process-Group-ID différent .

Longue histoire

> 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)"

Exécutez l'arborescence des processus en arrière-plan à l'aide de '&'

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

La commande pkill -P $PID ne tue pas le petit-enfant :

> 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

La commande kill -- -$PGID tue tous les processus, y compris le petit-enfant.

> 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

Conclusion

Je remarque dans cet exemple PID et PGID sont égaux (28957 ).
C'est pourquoi je pensais à l'origine kill -- -$PID était suffisant. Mais dans le cas où le processus est généré dans un Makefile l'ID de processus est différent de l'ID de groupe .

Je pense kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) est la meilleure astuce simple pour tuer tout un arbre de processus lorsqu'il est appelé à partir d'un ID de groupe différent (un autre arbre de processus).


pkill -TERM -P 27888

Cela tuera tous les processus qui ont l'ID de processus parent 27888.

Ou plus robuste :

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

qui planifie l'arrêt 33 secondes plus tard et demande poliment aux processus de se terminer.

Voir cette réponse pour mettre fin à tous les descendants.


Linux
  1. Linux - Ctrl + c peut-il envoyer le signal Sigint à plusieurs processus ?

  2. Quel processus utilise toutes mes E/S de disque

  3. Je viens de supprimer /bin. Quelle est la meilleure façon de récupérer ?

  4. Quand le système envoie-t-il un SIGTERM à un processus ?

  5. Quelle est la différence entre kill , pkill et killall ?

Comment lister les membres d'un groupe sous Linux

SIGTERM vs SIGKILL :Quelle est la différence ?

Qu'est-ce que la commande kill sous Linux ?

Qu'est-ce qu'un processus arrêté sous Linux ?

Quelle est la meilleure façon d'apprendre SELinux ?

Quel est le moyen le plus rapide de supprimer tous les fichiers et sous-dossiers d'un répertoire ?