Ich möchte einen ganzen Prozessbaum töten. Wie kann ich das am besten mit einer der gängigen Skriptsprachen erreichen? Ich bin auf der Suche nach einer einfachen Lösung.
Antworten
Zu viele Anzeigen?Das Folgende wurde auf FreeBSD, Linux und MacOS X getestet und hängt nur von pgrep und kill ab (die ps -o Versionen funktionieren nicht unter BSD). Das erste Argument ist die Eltern-Pid, deren Kinder terminiert werden müssen. Das zweite Argument ist ein Boolescher Wert, der bestimmt, ob die Eltern-Pid ebenfalls terminiert werden muss.
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
Dies sendet SIGTERM an jeden Kind-/Enkelprozess innerhalb eines Shell-Skripts und wenn SIGTERM nicht erfolgreich ist, wartet es 10 Sekunden und sendet dann kill.
Frühere Antwort:
Das Folgende funktioniert auch, wird aber unter BSD die Shell selbst beenden.
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
Danke für eure Weisheit, Leute. Mein Skript hat beim Beenden einige Kindprozesse hinterlassen und die Verneinung Tipp machte die Sache einfacher. Ich habe diese Funktion geschrieben, damit sie bei Bedarf in anderen Skripten verwendet werden kann:
# 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
}
Zum Wohl.
Ich entwickle die Lösung von zhigang, xyuri und solidsneck weiter:
#!/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
Diese Version vermeidet das Töten der Vorfahren, was bei den bisherigen Lösungen zu einer Flut von Kindprozessen führt.
Die Prozesse werden ordnungsgemäß gestoppt, bevor die Child-Liste ermittelt wird, so dass keine neuen Children erstellt werden oder verschwinden.
Nach dem Beenden müssen die angehaltenen Aufträge fortgesetzt werden, um aus dem System zu verschwinden.