Quelle est la meilleure façon d'envoyer un signal à tous les membres d'un groupe de processus?
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.
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 signalKILL
(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 deTERM
) -
kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(signal deKILL
)
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 deps opgid= $PID
ps -o pgid --no-headers $PID
oùpgid
peut être remplacé parpgrp
.
Mais:-
ps
inserts principaux espaces lorsquePID
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 $@
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,
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
}