467 Stimmen

Wie kann man am besten ein Signal an alle Mitglieder einer Prozessgruppe senden?

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.

339voto

Norman Ramsey Punkte 193087

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 .

235voto

oHo Punkte 45335

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 Signal KILL (9)

Sie können die PGID von jedem Prozess-ID ( PID ) desselben Prozessbaum

  • *`kill -- -$(ps -o pgid= $PID | grep -o '[0-9]')**   (SignalTERM` )
  • *`kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]')**   (SignalKILL` )

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 von ps opgid= $PID es ps -o pgid --no-headers $PID wobei pgid kann ersetzt werden durch pgrp .
    Aber:
    • ps fügt führende Leerzeichen ein, wenn PID weniger als fünf Ziffern hat und rechtsbündig ist, wie durch Tanager . Sie können verwenden:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps von OSX immer die Kopfzeile drucken, daher Speakus schlägt vor:
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • *`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).

173voto

Onlyjob Punkte 5323
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.

105voto

zhigang Punkte 5618

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 $@

31voto

Onlyjob Punkte 5323

rkill Befehl von pslist Paket sendet gegebenes Signal (oder SIGTERM standardmäßig) für den angegebenen Prozess und alle seine Nachkommen:

rkill [-SIG] pid/name...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X