it-swarm.com.de

Was ist der beste Weg, um ein Signal an alle Mitglieder einer Prozessgruppe zu senden?

Ich möchte einen ganzen Prozessbaum beenden. Was ist der beste Weg, dies mit gängigen Skriptsprachen zu tun? Ich suche eine einfache Lösung.

398
Adam Peck

Sie sagen nicht, ob der Baum, den Sie töten möchten, eine einzelne Prozessgruppe ist. (Dies ist häufig der Fall, wenn die Baumstruktur das Ergebnis ist, wenn Sie von einem Serverstart oder einer Shell-Befehlszeile aus fälschen.) Sie können 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 den Befehl kill(1). Geben Sie ihr jedoch keine Prozessnummer, sondern die Negation der Gruppennummer. Um beispielsweise jeden Prozess in Gruppe 5112 zu beenden, verwenden Sie kill -TERM -- -5112.

279
Norman Ramsey

Beenden Sie alle Prozesse, die zum selben Prozessbaum gehören, mit 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 jeder Prozess-ID (PID) desselben Prozessbaums abrufen.

  • kill -- -$(ps -o pgid= $PID | grep -o '[0-9]*') (Signal TERM)
  • kill -9 -$(ps -o pgid= $PID | grep -o '[0-9]*') (Signal KILL)

Besonderer Dank geht an tanager und Speakus für Beiträge zu _$PID_ verbleibendem Speicherplatz und OSX-Kompatibilität.

Erläuterung

  • kill -9 -"$PGID" => Sende Signal 9 (KILL) an alle Kinder und Enkelkinder ...
  • PGID=$(ps opgid= "$PID") => Rufe die Prozessgruppen-ID von einer Prozess-ID des Baums ab, nicht nur die Prozess-Eltern-ID . Eine Variation von ps opgid= $PID ist ps -o pgid --no-headers $PID, wobei pgid durch pgrp ersetzt werden kann.
    Aber:
    • ps fügt führende Leerzeichen ein, wenn PID weniger als fünf Stellen hat und rechtsbündig ausgerichtet ist, wie durch tanager bemerkt. Sie können verwenden:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps von OSX immer den Header ausgeben, daher Speakus vorschlägt:
      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 Kommandozeilen

_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)
_

Verjährung

  • Wie von davide und Hubert Kario bemerkt, wird kill von einem Prozess aufgerufen, der zum selben Baum gehört, kill Es besteht die Gefahr, sich selbst zu töten, bevor der gesamte Baum getötet wird.
  • Stellen Sie daher sicher, dass Sie den Befehl mit einem Prozess ausfü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)"
_

Starten Sie den Prozessbaum 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_ beendet alle Prozesse, einschließlich des Enkelkinds.

_> 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
_

Fazit

Ich bemerke in diesem Beispiel, dass PID und PGID gleich sind (_28957_).
Deshalb dachte ich ursprünglich, _kill -- -$PID_ sei genug. In dem Fall, dass der Prozess innerhalb einer Makefile erzeugt wird, unterscheidet sich die Prozess-ID von der Gruppen-ID .

Ich denke, kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) ist der beste einfache Trick, um einen gesamten Prozessbaum zu töten, wenn er von einer anderen Gruppen-ID (einem anderen Prozessbaum) aufgerufen wird.

191
olibre
pkill -TERM -P 27888

Dadurch werden alle Prozesse mit der übergeordneten Prozess-ID 27888 abgebrochen.

Oder robuster:

CPIDS=$(pgrep -P 27888); (sleep 33 && kill -KILL $CPIDS &); kill -TERM $CPIDS

der Zeitplan, der 33 Sekunden später getötet wird, und fordert höflich auf, Prozesse zu beenden.

Siehe diese Antwort , um alle Nachkommen zu beenden.

162
Onlyjob

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 [email protected]
99
zhigang

Das - rkill - Kommando aus dem - pslist - Paket sendet ein gegebenes Signal (oder standardmäßig SIGTERM) an den angegebenen Prozess und dessen Nachkommen:

rkill [-SIG] pid/name...
15
Onlyjob

brads Antwort ist das, was ich auch empfehlen würde, außer dass Sie awk ganz aufgeben können, wenn Sie die --ppid-Option für ps verwenden.

for child in $(ps -o pid -ax --ppid $PPID) do ....... done
11
Kim Stebel

Geänderte Version der Antwort von 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
9
x-yuri

Ich verwende eine etwas modifizierte Version einer hier beschriebenen Methode: https://stackoverflow.com/a/5311362/563175

So sieht es so aus:

kill `pstree -p 24901 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " "`

wobei 24901 die PID des Elternteils ist.

Es sieht ziemlich hässlich aus, macht aber seinen Job perfekt.

9
Tomasz Werszko

wenn Sie wissen, dass die PID des übergeordneten Prozesses übergeben wird, sollten Sie ein Shell-Skript verwenden, das funktionieren sollte:

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
9
brad.lane

Um Norman Ramseys Antwort hinzuzufügen, kann es sich lohnen, setsid zu betrachten, wenn Sie eine Prozessgruppe erstellen möchten.
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html

Die setsid () - Funktion erstellt eine neue Sitzung, wenn der aufrufende Prozess .__ ist. kein Prozessgruppenleiter. Auf Rückgabe des aufrufenden Prozesses lautet der Sitzungsleiter dieses neuen Sitzung ist die Prozessgruppe Leiter einer neuen Prozessgruppe und hat kein steuerndes Terminal . Die Prozessgruppen-ID des aufrufenden Prozess wird gleich gesetzt Prozess-ID des aufrufenden Prozesses. Das Aufrufprozess ist der einzige Prozess in der neuen Prozessgruppe und der einzige Prozess in der neuen Sitzung.

Ich meine damit, dass Sie vom Startprozess aus eine Gruppe erstellen können. Ich habe dies in PHP verwendet, um einen ganzen Prozessbaum nach dem Start zu beenden. 

Dies kann eine schlechte Idee sein. Ich würde mich für Kommentare interessieren. 

8
hajamie

Ich kann nicht kommentieren (nicht genug Ruf), also bin ich gezwungen, eine neue Antwort hinzuzufügen, auch wenn dies nicht wirklich eine Antwort ist.

Es gibt ein kleines Problem mit der ansonsten sehr schönen und umfassenden Antwort von @olibre am 28. Februar. Die Ausgabe von ps opgid= $PID enthält führende Leerzeichen für eine PID, die kürzer als fünf Stellen ist, da ps die Spalte rechtfertigt (genaues Ausrichten der Zahlen). In der gesamten Befehlszeile führt dies zu einem negativen Vorzeichen, gefolgt von Leerzeichen, gefolgt von der Gruppen-PID. Eine einfache Lösung besteht darin, ps an tr zu übergeben, um Leerzeichen zu entfernen:

kill -- -$( ps opgid= $PID | tr -d ' ' )
8
tanager

Inspiriert von ysth's Kommentar

kill -- -PGID

anstatt ihm eine Prozessnummer zu geben, geben Sie ihm die Negation der Gruppe Nummer. Wie bei fast jedem Befehl üblich, wenn Sie ein normales Argument möchten. beginnt mit einem -, um nicht als Schalter interpretiert zu werden, voranstellen mit --

7
Steven Penny

Die folgende Shell-Funktion ähnelt vielen anderen Antworten, funktioniert jedoch sowohl unter Linux als auch unter BSD (OS X usw.) ohne externe Abhängigkeiten wie 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
}

Dies ist mit Python unter Verwendung von psutil sehr einfach. Installieren Sie einfach psutil mit pip und Sie haben eine vollständige Suite von Tools zur Prozessbearbeitung:

def killChildren(pid):
    parent = psutil.Process(pid)
    for child in parent.get_children(True):
        if child.is_running():
            child.terminate()
5
genericdave

Wenn Sie einen Prozess nach Namen abbrechen möchten:

killall -9 -g someprocessname

oder

pgrep someprocessname | xargs pkill -9 -g
4
Mika Vatanen

Basierend auf der Antwort von zhigang werden Selbstmorde vermieden:

init_killtree() {
    local pid=$1 child

    for child in $(pgrep -P $pid); do
        init_killtree $child
    done
    [ $pid -ne $$ ] && kill -kill $pid
}
4
davide

Hier ist eine Variation der Antwort von @ zhigang, die ohne AWK auskommt und sich nur auf die systemeigenen Parsing-Möglichkeiten von Bash stützt:

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"
}

Es scheint gut auf Macs und Linux zu funktionieren. In Situationen, in denen Sie sich nicht darauf verlassen können, Prozessgruppen verwalten zu können, wie z. B. beim Erstellen von Skripts zum Testen einer Software, die in mehreren Umgebungen erstellt werden muss, ist diese Technik beim Baumgehen auf jeden Fall hilfreich.

3
solidsnack

Dies ist meine Version, alle untergeordneten Prozesse mit dem Bash-Skript zu beenden .. __ Sie verwendet keine Rekursion und hängt vom Befehl pgrep ab.

Benutzen 

killtree.sh PID SIGNAL

Inhalt von 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//,/ }
3
marekdef

Alte Frage, ich weiß, aber alle Antworten scheinen ps anzurufen, was mir nicht gefallen hat.

Diese awk-basierte Lösung erfordert keine Rekursion und ruft ps nur einmal auf.

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)
}'

Oder in einer Zeile:

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)}'

Grundsätzlich ist die Idee, dass wir ein Array (a) von Eltern-Kind-Einträgen aufbauen, dann das Array durchlaufen und nach Kindern für unsere passenden Eltern suchen, die wir unserer Elternliste hinzufügen (p).

Wenn Sie den Prozess der obersten Ebene nicht beenden möchten, tun Sie dies

sub(/[0-9]*/, "", p)

kurz bevor die system () - Zeile es aus dem Kill-Set entfernen würde.

Bedenken Sie, dass es hier eine Race-Bedingung gibt, aber das stimmt (soweit ich sehen kann) für alle Lösungen. Es macht, was ich brauchte, weil das Skript, für das ich es brauchte, nicht viele kurzlebige Kinder schafft.

Eine Übung für den Leser besteht darin, eine Schleife mit 2 Durchgängen zu erstellen: Senden Sie nach dem ersten Durchlauf SIGSTOP an alle Prozesse in der p-Liste, führen Sie dann eine Schleife aus, um ps erneut auszuführen, und senden Sie nach dem zweiten Durchlauf SIGTERM und dann SIGCONT. Wenn Sie sich nicht für schöne Enden interessieren, könnte der zweite Durchgang vielleicht SIGKILL sein, nehme ich an.

1
Whinger

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 es, ihre Vorfahren zu töten - was bei den vorherigen Lösungen eine Flut von untergeordneten Prozessen verursacht.

Prozesse werden ordnungsgemäß angehalten, bevor die untergeordnete Liste festgelegt wird, sodass keine neuen untergeordneten Objekte erstellt werden oder verschwinden.

Nach dem Abbruch müssen die gestoppten Jobs weiterhin aus dem System verschwinden. 

1
Peter Steier

Es ist wahrscheinlich besser, die Eltern vor den Kindern zu töten. Andernfalls können Eltern wahrscheinlich wieder neue Kinder hervorbringen, bevor sie selbst getötet werden. Diese werden das Töten überleben.

Meine Version von ps unterscheidet sich von der obigen; vielleicht zu alt, deshalb das seltsame Grepping ...

Die Verwendung eines Shell-Skripts anstelle einer Shell-Funktion hat viele Vorteile ...

Es ist jedoch im Grunde eine Zhigangs-Idee


#!/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
1
Peter Steier

Folgendes wurde unter 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, bei der Kinder gekündigt werden müssen. Das zweite Argument ist ein Boolescher Wert, um zu bestimmen, ob die übergeordnete PID ebenfalls beendet 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

Dadurch wird SIGTERM an jeden untergeordneten/Enkelprozess innerhalb eines Shell-Skripts gesendet. Wenn SIGTERM nicht erfolgreich ist, wartet es 10 Sekunden und sendet dann kill.


Frühere Antwort:

Das Folgende funktioniert auch, aber die Shell selbst wird auf BSD abgebrochen.

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
1
Orsiris de Jong

In sh listet der Befehl jobs die Hintergrundprozesse auf. In einigen Fällen ist es möglicherweise besser, den neuesten Prozess zuerst zu beenden, z. der ältere erstellte einen gemeinsamen Socket. In diesen Fällen sortieren Sie die PIDs in umgekehrter Reihenfolge. Manchmal möchten Sie warten, bis die Jobs etwas auf die Festplatte oder ähnliches schreiben, bevor sie angehalten werden.

Und töte nicht, wenn du nicht musst!

for SIGNAL in TERM KILL; do
  for CHILD in $(jobs -s|sort -r); do
    kill -s $SIGNAL $CHILD
    sleep $MOMENT
  done
done
0
jens

Wenn Sie die PID der Sache kennen, die Sie töten möchten, können Sie normalerweise von der Sitzungs-ID und von allem, was sich in derselben Sitzung befindet, gehen. Ich würde es noch einmal überprüfen, aber ich habe dies für Skripte verwendet, die Rsyncs in Schleifen starten, die ich sterben möchte, und keine anderen starten (wegen der Schleife), als würde ich einfach Rsync beenden.

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid 21709))

Wenn Sie die PID nicht kennen, können Sie noch mehr nisten

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))
0
Morgan

Danke für deine Weisheit, Leute. Mein Skript ließ einige untergeordnete Prozesse beim Beenden und der negationtip machte die Sache einfacher. Ich habe diese Funktion geschrieben, um sie bei Bedarf in anderen Skripten verwenden zu können:

# 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
}

Prost.

0
Donald Duck

Ich weiß, das ist alt, aber das ist die bessere Lösung, die ich gefunden habe:

killtree() { 
    for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
        echo Terminating: $p 
        kill $p
    done
}

wenn Sie Pstree und Perl auf Ihrem System installiert haben, können Sie Folgendes versuchen:

Perl -e 'kill 9, (`pstree -p PID` =~ m/\((\d+)\)/sg)'
0
lyman

Dieses Skript funktioniert auch:

#/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

0
Nullpointer

Töten Sie die Gruppe nur mit dem Namen des Prozesses, der zur Gruppe gehört:

kill -- -$(ps -ae o pid,pgrp,cmd | grep "[e]xample.py" | awk '{print $2}' | tail -1)

Dies ist eine Modifikation der Antwort von olibre, aber Sie müssen nicht die PID kennen, nur den Namen eines Mitglieds der Gruppe. 

Erläuterung:

Um die Gruppen-ID zu erhalten, führen Sie den Befehl ps mit den angegebenen Argumenten aus, grep es für Ihren Befehl, formatiert jedoch example.py mit Anführungszeichen und verwendet die Klammer für den ersten Buchstaben (dies filtert den grep-Befehl selbst heraus) awk, um das zweite Feld zu erhalten, das die Gruppennummer ist. Der Schwanz -1 entfernt doppelte Gruppen-IDs. Sie fügen all dies in eine Variable mit der $ () - Syntax und voila ein - Sie erhalten die Gruppen-ID. Sie ersetzen also diese $ -Gruppe von oben. 

0
CoderBlue
ps -o pid= --ppid $PPID | xargs kill -9 
0
Harpreet

Kindprozess in Shell-Skript beenden:

Viele Male müssen wir Kinderprozesse töten, die aus irgendeinem Grund gehängt oder blockiert werden. z.B. Problem mit der FTP-Verbindung.

Es gibt zwei Ansätze:

1) Für jedes Kind einen eigenen neuen Elternteil erstellen, der den untergeordneten Prozess überwacht und beendet, sobald das Timeout erreicht ist.

Erstellen Sie test.sh wie folgt:

#!/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;

und beobachten Prozesse, die einen Namen als 'test' haben, in folgendem Befehl.

watch -n1 'ps x -o "%p %r %c" | grep "test" '

Das obige Skript erstellt 4 neue untergeordnete Prozesse und deren Eltern. Jeder untergeordnete Prozess wird für 10 Sekunden ausgeführt. Sobald jedoch die Zeitspanne von 5 Sekunden überschritten wird, töten die jeweiligen übergeordneten Prozesse diese untergeordneten Elemente. Damit kann das Kind die Ausführung nicht abschließen (10 Sekunden). Spielen Sie mit diesen Timings (Schalter 10 und 5), um ein anderes Verhalten zu sehen. In diesem Fall beendet das Kind die Ausführung in 5 Sekunden, bevor es eine Zeitüberschreitung von 10 Sekunden erreicht.

2) Lassen Sie das aktuelle Elternteil überwachen und beenden, sobald das Timeout erreicht ist. Dadurch werden keine separaten übergeordneten Elemente erstellt, um jedes untergeordnete Element zu überwachen. Sie können auch alle untergeordneten Prozesse innerhalb derselben übergeordneten Komponente ordnungsgemäß verwalten.

Erstellen Sie test.sh wie folgt:

#!/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;

und beobachten Prozesse, die einen Namen als 'test' haben, in folgendem Befehl.

watch -n1 'ps x -o "%p %r %c" | grep "test" '

Das obige Skript erstellt 4 neue untergeordnete Prozesse. Wir speichern PIDs aller untergeordneten Prozesse und führen eine Schleife über sie durch, um zu prüfen, ob sie mit ihrer Ausführung fertig sind oder noch laufen .. _. Die untergeordnete Verarbeitung wird bis zum CMD_TIME-Zeitpunkt ausgeführt. Wenn jedoch das CNT_TIME_OUT-Timeout erreicht wird, werden alle Kinder durch den übergeordneten Prozess getötet. Sie können das Timing ändern und mit dem Skript herumspielen, um das Verhalten zu sehen. Ein Nachteil dieser Methode ist die Verwendung der Gruppen-ID zum Töten aller Kinder Baum. Der übergeordnete Prozess selbst gehört jedoch derselben Gruppe an, daher wird er auch getötet.

Möglicherweise müssen Sie dem übergeordneten Prozess eine andere Gruppen-ID zuweisen, wenn Sie nicht möchten, dass der übergeordnete Prozess beendet wird.

Weitere Details finden Sie hier

Töten eines untergeordneten Prozesses in einem Shell-Skript

0
Hemant Thorat