Sie sagen nicht, ob der Baum, den Sie töten möchten, eine einzelne Prozessgruppe ist. (Dies ist häufig der Fall, wenn der Baum das Ergebnis einer Verzweigung von einem Serverstart oder einer Shell-Befehlszeile ist.) Sie können Prozessgruppen mit GNU ps wie folgt entdecken:
ps x -o "%p %r %y %x %c "
Wenn Sie eine Prozessgruppe beenden möchten, verwenden Sie einfach den kill(1)
Befehl, aber anstatt ihm eine Prozessnummer zu geben, geben Sie ihm die Negation der Gruppennummer. Um beispielsweise jeden Prozess in Gruppe 5112 zu beenden, verwenden Sie kill -TERM -- -5112
.
Beenden Sie alle Prozesse, die zum selben Prozessbaum gehören unter Verwendung der Prozessgruppen-ID (PGID
)
kill -- -$PGID
Standardsignal verwenden (TERM
=15)kill -9 -$PGID
Verwenden Sie das SignalKILL
(9)
Sie können den PGID
abrufen von einer beliebigen Prozess-ID (PID
) desselben Prozessbaums
kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*')
(SignalTERM
)kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*')
(SignalKILL
)
Erklärung
kill -9 -"$PGID"
=> Signal 9 senden (KILL
) an alle Kinder und Enkelkinder...PGID=$(ps opgid= "$PID")
=> Rufen Sie die Prozessgruppen-ID ab von einer beliebigen Prozess-ID des Baums, nicht nur die Process-Parent-ID . Eine Variation vonps opgid= $PID
istps -o pgid --no-headers $PID
wobeipgid
kann durchpgrp
ersetzt werden .
Aber:ps
fügt führende Leerzeichen ein, wennPID
ist weniger als fünf Ziffern und rechtsbündig, wie von Tanager bemerkt. Sie können Folgendes verwenden:
PGID=$(ps opgid= "$PID" | tr -d ' ')
ps
von OSX immer den Header drucken, daher schlägt Speakus vor:
PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
grep -o [0-9]*
druckt nur aufeinanderfolgende Ziffern (druckt keine Leerzeichen oder alphabetischen Ü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)
Einschränkung
- Wie von Davide und Hubert Kario bemerkt, als
kill
wird von einem Prozess aufgerufen, der zu demselben Baum gehört,kill
riskiert, sich selbst zu töten, bevor das Töten des gesamten Baums beendet wird. - Achten Sie daher darauf, den Befehl mit einem Prozess auszuführen, der eine andere Prozessgruppen-ID hat .
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)"
Führen Sie den Prozessbaum mit '&'
im Hintergrund aus> ./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
beendet 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
Ich bemerke in diesem Beispiel PID
und PGID
gleich sind (28957
).
Deshalb dachte ich ursprünglich an kill -- -$PID
war genug. Aber in dem Fall wird der Prozess innerhalb eines Makefile
erzeugt die Prozess-ID unterscheidet sich von der 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 einer anderen Gruppen-ID aufgerufen wird (ein weiterer Prozessbaum).
pkill -TERM -P 27888
Dadurch werden alle Prozesse beendet, die die übergeordnete Prozess-ID 27888 haben.
Oder robuster:
CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS
die das Töten 33 Sekunden später planen und Prozesse höflich bitten, sich zu beenden.
Siehe diese Antwort zum Beenden aller Nachkommen.