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?Sie geben nicht an, ob der Baum, den Sie beenden wollen, eine einzelne Prozessgruppe ist. (Das ist oft der Fall, wenn der Baum das Ergebnis eines Forks von einem Serverstart oder einer Shell-Befehlszeile ist.) Du kannst Prozessgruppen mit GNU ps wie folgt ermitteln:
ps x -o "%p %r %y %x %c "
Wenn es sich um eine Prozessgruppe handelt, die Sie beenden möchten, verwenden Sie einfach die kill(1)
Befehl, aber anstatt ihm eine Prozessnummer zu geben, geben Sie ihm die Verneinung der Gruppennummer. Um zum Beispiel alle Prozesse in der Gruppe 5112 zu beenden, verwenden Sie kill -TERM -- -5112
.
Beenden Sie alle Prozesse, die zu demselben Prozessbaum unter Verwendung der Prozessgruppen-ID ( PGID
)
kill -- -$PGID
Standardsignal verwenden (TERM
= 15)kill -9 -$PGID
Verwenden Sie das SignalKILL
(9)
Sie können die PGID
von jedem Prozess-ID ( PID
) desselben Prozessbaum
- *`kill -- -$(ps -o pgid= $PID | grep -o '[0-9]')
** (Signal
TERM` ) - *`kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]')
** (Signal
KILL` )
Besonderen Dank an Tanager y Speakus für Beiträge zu $PID
Restplätze und OSX-Kompatibilität.
Erläuterung
kill -9 -"$PGID"
=> Signal 9 senden (KILL
) an alle Kinder und Enkelkinder...PGID=$(ps opgid= "$PID")
=> Rufen Sie die Prozess-Gruppen-ID von jedem Prozess-ID des Baumes, nicht nur die Prozess-Eltern-ID . Eine Variante vonps opgid= $PID
esps -o pgid --no-headers $PID
wobeipgid
kann ersetzt werden durchpgrp
.
Aber:- *`grep -o [0-9]`** druckt nur aufeinander folgende Ziffern (keine Leerzeichen oder alphabetische Überschriften).
Weitere Befehlszeilen
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)
Begrenzung
- Wie von davide y Hubert Kario wenn
kill
von einem Prozess aufgerufen wird, der zu demselben Baum gehört,kill
riskiert, sich selbst zu töten, bevor er das Töten des gesamten Baumes beendet. - Stellen Sie daher sicher, dass Sie den Befehl mit einem Prozess ausführen, der einen anderen Prozess-Gruppen-ID .
Lange Geschichte
> 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)"
Ausführen des Prozessbaums im Hintergrund mit '&'
> ./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
Der Befehl pkill -P $PID
tötet das Enkelkind nicht:
> 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
Der Befehl kill -- -$PGID
tötet alle Prozesse einschließlich des Enkels.
> 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
Schlussfolgerung
Bei diesem Beispiel fällt mir auf PID
y PGID
gleich sind ( 28957
).
Aus diesem Grund dachte ich ursprünglich kill -- -$PID
war genug. Aber in dem Fall, dass der Prozess innerhalb einer Makefile
die Prozess-ID ist anders als die Gruppen-ID .
Ich denke *`kill -- -$(ps -o pgid= $PID | grep -o [0-9])`** ist der beste einfache Trick, um einen ganzen Prozessbaum zu beenden, wenn er von einem anderen Gruppen-ID (ein weiterer Prozessbaum).
pkill -TERM -P 27888
Dies wird alle Prozesse mit der übergeordneten Prozess-ID 27888 beenden.
Oder noch robuster:
CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS
die das Töten 33 Sekunden später vorsehen und Prozesse höflich bitten, sich zu beenden.
Ver diese Antwort für die Beendigung aller Nachkommen.
Um einen Prozessbaum rekursiv zu beenden, verwenden Sie 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 $@
- See previous answers
- Weitere Antworten anzeigen