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

StackOverflow https://stackoverflow.com/questions/392022

  •  23-08-2019
  •  | 
  •  

Question

Je veux tuer un arbre de processus. Quelle est la meilleure façon de le faire en utilisant les langages de script commun? Je suis à la recherche d'une solution simple.

Était-ce utile?

La solution

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

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

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

Autres conseils

tuer tous les processus appartenant à la même arbre de processus avec Process Group ID (PGID)

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

Vous pouvez récupérer le PGID de tout Processus ID (PID) du même arbre processus

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

Merci à Tangara et Speakus pour les contributions sur les espaces restants de $PID et la compatibilité OSX.

Explication

  • kill -9 -"$PGID" => Envoyer le signal 9 (KILL) à tous les enfants et petits-enfants ...
  • PGID=$(ps opgid= "$PID") => Récupérer le Process-GID de tout Processus ID de l'arbre, non seulement le Processus -Parent-ID . Une variante de ps opgid= $PID ps -o pgid --no-headers $PID pgid peut être remplacé par pgrp .
    Mais:
    • ps inserts principaux espaces lorsque PID est inférieur à cinq chiffres et aligné à droite comme remarqué par Tangara . Vous pouvez utiliser:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps à partir de Mac OS X toujours imprimer l'en-tête, donc Speakus propose:
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • grep -o [0-9]* imprime chiffres successifs uniquement (n'imprime pas des espaces ou des en-têtes par ordre alphabétique).

D'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)

Limitation

  • Comme remarqué par et Hubert Kario , quand kill est invoquée par un processus appartenant au même arbre, kill les risques de se tuer avant de terminer toute mise à mort de l'arbre.
  • Par conséquent, assurez-vous d'exécuter la commande au moyen d'un processus ayant un autre Process-GID .

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écuter l'arborescence des processus en arrière-plan en utilisant '&'

> ./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).
Voilà pourquoi je pensais à l'origine kill -- -$PID suffisait. Mais dans le cas où le processus est fraient dans un Makefile ID de processus est différent de ID de groupe .

Je pense que kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) est la meilleure astuce simple de tuer un arbre de processus est appelé depuis un autre ID de groupe (un autre arbre de processus).

pkill -TERM -P 27888

Cela tue tous les processus qui ont le processus parent ID 27888.

Ou plus robuste:

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

qui calendrier tuant 33 secondes plus tard et demander poliment de mettre fin à des processus.

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

Pour tuer un arbre de processus récursif, l'utilisation killtree ():

#!/bin/bash

killtree() {
    local _pid=$1
    local _sig=${2:--TERM}
    kill -stop ${_pid} # needed to stop quickly forking parent from producing children between child killing and parent killing
    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
        killtree ${_child} ${_sig}
    done
    kill -${_sig} ${_pid}
}

if [ $# -eq 0 -o $# -gt 2 ]; then
    echo "Usage: $(basename $0) <pid> [signal]"
    exit 1
fi

killtree $@

rkill commande de pslist paquet envoie un signal donné (ou SIGTERM par défaut) pour processus spécifié et tous ses descendants:

rkill [-SIG] pid/name...

La réponse de brad est ce que je vous recommande aussi, sauf que vous pouvez faire disparaître awk tout à fait si vous utilisez l'option --ppid à ps.

for child in $(ps -o pid -ax --ppid $PPID) do ....... done

si vous savez passer le pid du processus parent, voici un script shell qui devrait fonctionner:

for child in $(ps -o pid,ppid -ax | \
   awk "{ if ( \$2 == $pid ) { print \$1 }}")
do
  echo "Killing child process $child because ppid = $pid"
  kill $child
done

J'utilise un peu d'une version modifiée méthode décrite ici: https://stackoverflow.com/a/5311362/563175

Il ressemble à ça:

kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`

où 24901 est le PID parent.

Il semble assez laid mais est-ce est parfaitement travail.

version modifiée de la réponse Zhigang:

#!/usr/bin/env bash
set -eu

killtree() {
    local pid
    for pid; do
        kill -stop $pid
        local cpid
        for cpid in $(pgrep -P $pid); do
            killtree $cpid
        done
        kill $pid
        kill -cont $pid
        wait $pid 2>/dev/null || true
   done
}

cpids() {
    local pid=$1 options=${2:-} space=${3:-}
    local cpid
    for cpid in $(pgrep -P $pid); do
        echo "$space$cpid"
        if [[ "${options/a/}" != "$options" ]]; then
            cpids $cpid "$options" "$space  "
        fi
    done
}

while true; do sleep 1; done &
cpid=$!
for i in $(seq 1 2); do
    cpids $$ a
    sleep 1
done
killtree $cpid
echo ---
cpids $$ a

Je ne peux pas commenter (pas assez réputation), donc je suis obligé d'ajouter une nouvelle réponse , même si ce n'est pas vraiment une réponse.

Il y a un léger problème avec la réponse par ailleurs très agréable et complet donné par @olibre le 28 février La sortie de ps opgid= $PID contiendra des espaces plus grands pour un PID inférieur à cinq chiffres, car ps justifie la colonne (aligner rigth les numéros ). Au sein de l'ensemble de la ligne de commande, cela se traduit par un signe négatif, suivie d'espace (s), suivi par le groupe PID. Une solution simple est de tuyau ps à tr pour supprimer les espaces:

kill -- -$( ps opgid= $PID | tr -d ' ' )

Pour ajouter à la réponse de Norman Ramsey, il peut être intéressant de regarder à setsid si vous voulez créer un groupe de processus.
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html

  

La fonction setsid () crée un   nouvelle session, si le processus d'appel est   pas un chef de groupe de processus. Sur   retour le processus d'appel sont   le leader de la session de cette nouvelle   session, est le groupe de processus   chef d'un nouveau groupe de processus, et   aura pas de terminal de contrôle.   Le groupe de processus de l'appel   processus doit être égal au   ID de processus du processus d'appel. le   processus d'appel est le seul   procédé dans le nouveau groupe de processus et   le seul processus de la nouvelle session.

Ce que je prends à dire que vous pouvez créer un groupe à partir du processus de démarrage. J'ai utilisé ce en php pour être capable de tuer un arbre de processus après l'avoir démarré.

Cela peut être une mauvaise idée. Je serais intéressé par les commentaires.

Inspiré par Commentaire de la ysth

kill -- -PGID
  

au lieu de lui donner un certain nombre de processus, donner la négation du groupe   nombre. Comme d'habitude avec presque toutes les commandes, si vous voulez un argument normal   commence par un - de ne pas être interprétées comme un interrupteur, faites précéder avec --

La fonction shell suivante est similaire à la plupart des autres réponses, mais il fonctionne aussi bien sur Linux et BSD (OS X, etc) sans dépendances externes comme pgrep:

killtree() {
    local parent=$1 child
    for child in $(ps -o ppid= -o pid= | awk "\$1==$parent {print \$2}"); do
        killtree $child
    done
    kill $parent
}

Il est super facile à faire avec python en utilisant psutil . Il suffit d'installer psutil avec pip et vous avez une gamme complète d'outils de manipulation de processus:

def killChildren(pid):
    parent = psutil.Process(pid)
    for child in parent.get_children(True):
        if child.is_running():
            child.terminate()

Sur la base de la réponse de Zhigang, cela évite l'auto-meurtre:

init_killtree() {
    local pid=$1 child

    for child in $(pgrep -P $pid); do
        init_killtree $child
    done
    [ $pid -ne $$ ] && kill -kill $pid
}

Si vous voulez tuer un processus par son nom:

killall -9 -g someprocessname

ou

pgrep someprocessname | xargs pkill -9 -g

Ceci est ma version de tuer tous les processus enfants à l'aide de script bash. Il n'utilise pas récursivité et dépend de la commande pgrep.

Utilisez

killtree.sh PID SIGNAL

Contenu de killtrees.sh

#!/bin/bash
PID=$1
if [ -z $PID ];
then
    echo "No pid specified"
fi

PPLIST=$PID
CHILD_LIST=`pgrep -P $PPLIST -d,`

while [ ! -z "$CHILD_LIST" ]
do
    PPLIST="$PPLIST,$CHILD_LIST"
    CHILD_LIST=`pgrep -P $CHILD_LIST -d,`
done

SIGNAL=$2

if [ -z $SIGNAL ]
then
    SIGNAL="TERM"
fi
#do substring from comma to space
kill -$SIGNAL ${PPLIST//,/ }

Voici une variation de la réponse de @ Zhigang qui fait sans AWK, en se fondant uniquement sur les possibilités d'analyse syntaxique natif de Bash:

function killtree {
  kill -STOP "$1"
  ps -e -o pid= -o ppid= | while read -r pid ppid
                           do
                             [[ $ppid = $1 ]] || continue
                             killtree "$pid"  || true # Skip over failures
                           done
  kill -CONT "$1"          
  kill -TERM "$1"
}

Il semble fonctionner très bien sur Mac et Linux. Dans les situations où vous ne pouvez pas compter sur d'être en mesure de gérer des groupes de processus - comme lors de l'écriture des scripts pour tester un logiciel qui doit être construit en plusieurs environnements -. Cette technique d'arbres à pied est certainement utile

Merci pour votre sagesse, les gens. Mon script quittait des processus enfants à la sortie et la pointe négation a facilité les choses. J'ai écrit cette fonction à utiliser dans d'autres scripts si nécessaire:

# kill my group's subprocesses:          killGroup
# kill also myself:                      killGroup -x
# kill another group's subprocesses:     killGroup N  
# kill that group all:                   killGroup -x N
# N: PID of the main process (= process group ID).

function killGroup () {
    local prid mainpid
    case $1 in
        -x) [ -n "$2" ] && kill -9 -$2 || kill -9 -$$ ;;
        "") mainpid=$$ ;;
         *) mainpid=$1 ;;
    esac
    prid=$(ps ax -o pid,pgid | grep $mainpid)
    prid=${prid//$mainpid/}
    kill -9 $prid 2>/dev/null
    return
}

Vive.

Il est sans doute préférable de tuer le parent devant les enfants; sinon le parent peut probablement faire naître de nouvelles à nouveau des enfants avant qu'il ne soit lui-même tué. Ceux-ci survivront à la mort.

Ma version de ps est différent de celui ci-dessus; peut-être trop vieux, donc l'Grepping étrange ...

Pour utiliser un script shell au lieu d'une fonction shell présente de nombreux avantages ...

Cependant, il est essentiellement zhigangs idée


#!/bin/bash
if test $# -lt 1 ; then
    echo >&2 "usage: kiltree pid (sig)"
fi ;

_pid=$1
_sig=${2:-TERM}
_children=$(ps j | grep "^[ ]*${_pid} " | cut -c 7-11) ;
echo >&2 kill -${_sig} ${_pid}
kill -${_sig} ${_pid}
for _child in ${_children}; do
    killtree ${_child} ${_sig}
done

Ce qui suit a été testé sur FreeBSD, Linux et Mac OS X et ne dépend que de pgrep et de tuer (les versions ps -o ne fonctionnent pas sous BSD). Le premier argument est pid parents dont les enfants doivent être mis fin. second argument est une valeur booléenne pour déterminer si le pid-mère doit être terminé aussi.

KillChilds() {
        local pid="${1}"
        local self="${2:-false}"

        if children="$(pgrep -P "$pid")"; then
                for child in $children; do
                        KillChilds "$child" true
                done
        fi

        if [ "$self" == true ]; then
                kill -s SIGTERM "$pid" || (sleep 10 && kill -9 "$pid" &)
        fi
}

KillChilds $$ > /dev/null 2>&1

envoie SIGTERM à tout processus enfant / petit-enfant dans un script shell et si SIGTERM ne réussit pas, il attendra 10 secondes, puis envoyer tuer.


Un peu plus tôt réponse:

Ce qui suit fonctionne aussi, mais va tuer la coque elle-même sur BSD.

KillSubTree() {
    local parent="${1}"
    for child in $(ps -o pid=$parent); do
            if [ $$ -ne $child ]; then (kill -s SIGTERM $child || (sleep 10 && kill -9 $child & )) > /dev/null 2>&1 ; fi
    done
}
# Example lanch from within script
KillSubTree $$ > /dev/null 2>&1

Je développe la solution de Zhigang, xyuri et solidsneck plus:

 #!/bin/bash

if test $# -lt 1 ; then
    echo >&2 "usage: kiltree pid (sig)"
    exit 1 ;
  fi ;

_pid=$1
_sig=${2:-TERM}

# echo >&2 "killtree($_pid) mypid = $$"
# ps axwwf | grep -6 "^[ ]*$_pid " >&2 ;

function _killtree () {
    local _children
    local _child
    local _success

    if test $1 -eq $2 ; then # this is killtree - don't commit suicide!
        echo >&2 "killtree can´t kill it´s own branch - some processes will survive." ; 
        return 1 ;
      fi ;
    # this avoids that children are spawned or disappear.
    kill -SIGSTOP $2 ;

    _children=$(ps -o pid --no-headers --ppid $2) ;        
    _success=0 
    for _child in ${_children}; do
        _killtree $1 ${_child} $3 ;
        _success=$(($_success+$?)) ;
      done ;

    if test $_success -eq 0 ; then
        kill -$3 $2
      fi ;
    # when a stopped process is killed, it will linger in the system until it is continued
    kill -SIGCONT $2
    test $_success -eq 0 ;
    return $?
    }

_killtree $$ $_pid $_sig

Cette version évitera de tuer ses ancêtres -. Ce qui provoque une inondation de processus enfants dans les solutions précédentes

Les processus sont correctement arrêtés avant la liste des enfants est déterminée, de sorte qu'aucun nouvel enfant sont créés ou disparaissent.

Après avoir été tué, les emplois doivent être arrêtés continue à disparaître du système.

question Vieux, je sais, mais toutes les réponses semblent continuer à appeler ps, ce qui ne me plaisait pas.

Cette solution awk ne nécessite pas récursion et n'appelle ps une fois.

awk 'BEGIN {
  p=1390
  while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2
  o=1
  while (o==1) {
    o=0
    split(p, q, " ")
    for (i in q) if (a[q[i]]!="") {
      p=p""a[q[i]]
      o=1
      a[q[i]]=""
    }
  }
  system("kill -TERM "p)
}'

Ou sur une seule ligne:

awk 'BEGIN {p=1390;while ("ps -o ppid,pid"|getline) a[$1]=a[$1]" "$2;o=1;while (o==1) {o=0;split(p, q, " ");for (i in q) {if (a[q[i]]!="") {p=p""a[q[i]];o=1;a[q[i]]=""}}}system("kill -TERM "p)}'

En fait, l'idée est que nous construisons un tableau (a) de parent:. Entrées enfant, puis la boucle autour du réseau recherche d'enfants pour nos parents correspondants, les ajouter à notre liste des parents (p) que nous allons

Si vous ne voulez pas tuer le processus de niveau supérieur, puis en faisant

sub(/[0-9]*/, "", p)

juste avant la ligne système () se retirer de l'ensemble kill.

Gardez à l'esprit qu'il ya une condition de course, mais c'est vrai (pour autant que je peux voir) de toutes les solutions. Il fait ce que je avais besoin parce que le script je l'ai besoin pour ne crée pas beaucoup d'enfants de courte durée.

Un exercice pour le lecteur serait de faire une boucle de 2 passe: après le premier passage, envoyer SIGSTOP à tous les processus dans la liste p, puis la boucle pour exécuter ps à nouveau et après le deuxième passage envoyer SIGTERM, puis SIGCONT . Si vous ne se soucient pas de terminaisons belles alors deuxième passage pourrait juste être SIGKILL, je suppose.

si vous avez pstree et perl sur votre système, vous pouvez essayer ceci:

perl -e 'kill 9, (`pstree -p PID` =~ m/\((\d+)\)/sg)'

Si vous connaissez le pid de la chose que vous voulez tuer, vous pouvez aller habituellement de l'identifiant de session, et tout dans la même session. Je ferais une double vérification, mais je cela pour des scripts à partir rsyncs dans les boucles que je veux mourir, et non une autre commence (à cause de la boucle) comme il le ferait si je venais de rsync killall'd.

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))

Si vous ne connaissez pas le pid vous pouvez toujours nid plus

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))
ps -o pid= --ppid $PPID | xargs kill -9 

Dans sh la commande jobs énumérera les processus d'arrière-plan. Dans certains cas, il pourrait être préférable de tuer le nouveau processus d'abord, par exemple le plus ancien a créé une douille commune. Dans ces cas trier les PIDs dans l'ordre inverse. Parfois, vous voulez attendre un moment pour les travaux d'écrire quelque chose sur disque ou des trucs comme ça avant de cesser.

Et ne tuez pas si vous n'avez pas!

for SIGNAL in TERM KILL; do
  for CHILD in $(jobs -s|sort -r); do
    kill -s $SIGNAL $CHILD
    sleep $MOMENT
  done
done

Tuer processus enfant en script shell:

Beaucoup de temps nous avons besoin de tuer le processus fils qui sont pendus ou bloc pour une raison quelconque. par exemple. problème de connexion FTP.

Il existe deux approches,

1) Pour créer un nouveau parent pour chaque enfant qui contrôlera et tuer processus enfant une fois atteint délai.

Créer test.sh comme suit,

#!/bin/bash

declare -a CMDs=("AAA" "BBB" "CCC" "DDD")
for CMD in ${CMDs[*]}; do
    (sleep 10 & PID=$!; echo "Started $CMD => $PID"; sleep 5; echo "Killing $CMD => $PID"; kill $PID; echo "$CMD Completed.") &
done
exit;

et regarder les processus qui ont des nom « test » dans d'autres terminaux en utilisant la commande suivante.

watch -n1 'ps x -o "%p %r %c" | grep "test" '

Au-dessus de script crée 4 nouveaux processus enfants et leurs parents. Chaque processus enfant se déroulera pour 10sec. Mais une fois délai de portée 5sec, thier processus parents respectifs tueront ces Childs. Ainsi, l'enfant ne sera pas en mesure d'achever l'exécution (10sec). Jouez les timings (commutateur 10 et 5) pour voir un autre comportement. Dans ce cas, l'enfant terminera l'exécution en 5sec avant qu'il atteigne délai de 10 s.

2) Soit le moniteur parent actuel et tuer processus enfant une fois atteint délai. Cela ne crée pas parent séparé pour surveiller chaque enfant. vous pouvez également gérer tous les processus de l'enfant correctement dans même parent.

Créer test.sh comme suit,

#!/bin/bash

declare -A CPIDs;
declare -a CMDs=("AAA" "BBB" "CCC" "DDD")

CMD_TIME=15;
for CMD in ${CMDs[*]}; do
    (echo "Started..$CMD"; sleep $CMD_TIME; echo "$CMD Done";) &
    CPIDs[$!]="$RN";
    sleep 1;
done

GPID=$(ps -o pgid= $$);
CNT_TIME_OUT=10;
CNT=0;
while (true); do
    declare -A TMP_CPIDs;

    for PID in "${!CPIDs[@]}"; do
        echo "Checking "${CPIDs[$PID]}"=>"$PID;

        if ps -p $PID > /dev/null ; then
          echo "-->"${CPIDs[$PID]}"=>"$PID" is running..";
          TMP_CPIDs[$PID]=${CPIDs[$PID]};
        else
          echo "-->"${CPIDs[$PID]}"=>"$PID" is completed.";
        fi
    done

    if [ ${#TMP_CPIDs[@]} == 0 ]; then
        echo "All commands completed.";
        break;
    else
        unset CPIDs;
        declare -A CPIDs;
        for PID in "${!TMP_CPIDs[@]}"; do
            CPIDs[$PID]=${TMP_CPIDs[$PID]};
        done
        unset TMP_CPIDs;

        if [ $CNT -gt $CNT_TIME_OUT ]; then
            echo ${CPIDs[@]}"PIDs not reponding. Timeout reached $CNT sec. killing all childern with GPID $GPID..";
            kill -- -$GPID;
        fi
    fi

    CNT=$((CNT+1));
    echo "waiting since $b secs..";
    sleep 1;
done

exit;

et regarder les processus qui ont des nom « test » dans d'autres terminaux en utilisant la commande suivante.

watch -n1 'ps x -o "%p %r %c" | grep "test" '

Au-dessus de script crée 4 nouveaux processus enfants. Nous stockons pid de tous les processus de l'enfant et en boucle sur eux pour vérifier si elles ont terminé leur exécution ou encore en cours d'exécution. processus d'exécution enfant jusqu'à l'heure CMD_TIME. Mais si délai CNT_TIME_OUT atteindre, Tous les enfants vont se faire tuer par processus parent. Vous pouvez changer le calendrier et jouer avec le script pour voir le comportement. Un inconvénient de cette approche est, il utilise l'identifiant de groupe pour tuer tous les arbres de l'enfant. Mais processus parent lui-même appartiennent à un même groupe il sera également se faire tuer.

Vous devrez peut-être attribuer un autre identifiant de groupe processus parent si vous ne voulez pas le parent à tuer.

Vous trouverez plus de détails ici,

Tuer processus enfant dans le script shell

Ce script fonctionne aussi:

#/bin/sh while true do echo "Enter parent process id [type quit for exit]" read ppid if [ $ppid -eq "quit" -o $ppid -eq "QUIT" ];then exit 0 fi for i in `ps -ef| awk '$3 == '$ppid' { print $2 }'` do echo killing $i kill $i done done

Je sais que ce qui est vieux, mais c'est la meilleure solution que je trouve:

killtree() { 
    for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
        echo Terminating: $p 
        kill $p
    done
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top