Qual è il modo migliore per inviare un segnale a tutti i membri di un gruppo di processi?

StackOverflow https://stackoverflow.com/questions/392022

  •  23-08-2019
  •  | 
  •  

Domanda

Voglio uccidere un intero albero di processi.Qual è il modo migliore per farlo utilizzando i linguaggi di scripting più comuni?Sto cercando una soluzione semplice.

È stato utile?

Soluzione

Non si dice se l'albero si vuole uccidere è un unico gruppo di processi. (Questo è spesso il caso se l'albero è il risultato di biforcano da un inizio server o una riga di comando di shell.) Si possono scoprire gruppi di processo utilizzando GNU ps come segue:

 ps x -o  "%p %r %y %x %c "

Se si tratta di un gruppo di processi si vuole uccidere, basta usare il comando kill(1) ma invece di dare un numero di processo, dare il negazione del numero di gruppo. Ad esempio, per uccidere tutti i processi nel gruppo 5112, utilizzare kill -TERM -- -5112.

Altri suggerimenti

Uccidete tutti i processi appartenenti alla stessa albero processo con il Process ID gruppo (PGID)

  • kill -- -$PGID segnale Utilizzare predefinito (TERM = 15)
  • kill -9 -$PGID Utilizzare la KILL del segnale (9)

È possibile recuperare il PGID da qualsiasi Processo-ID (PID) dello stesso albero processo

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

Un ringraziamento speciale a tanager e Speakus per i contributi su $PID rimanenti spazi e compatibilità OSX.

Spiegazione

  • kill -9 -"$PGID" => Invia segnale 9 (KILL) per tutti i bambini e nipote ...
  • PGID=$(ps opgid= "$PID") => Recuperare il Processo-Group-ID da qualsiasi em> Processo-ID di un albero, non solo l'em> Processo << -parent-ID . Una variante di ps opgid= $PID è ps -o pgid --no-headers $PID dove pgid può essere sostituito da pgrp .
    Ma:
    • ps inserti spazi iniziali quando PID è inferiore a cinque cifre e destra allineate come notato da tanager . È possibile utilizzare:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps da OSX stampare sempre l'intestazione, quindi Speakus propone:
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • grep -o [0-9]* le stampe successive solo cifre (non stampa gli spazi o le intestazioni alfabetici).

Ulteriori linee di comando

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)

Limitazione

  • Come notato da davide e Hubert Kario , quando kill viene invocata da un processo che appartiene al medesimo albero, kill i rischi di uccidere se stessa prima di terminare l'intero albero uccisione.
  • Pertanto, assicurarsi di eseguire il comando utilizzando un procedimento avente un diverso Processo-Group-ID .

Per farla

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

Esegui l'albero processo in background utilizzando '&'

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

Il pkill -P $PID comando non uccide il nipote:

> 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

Il comando di kill -- -$PGID uccide tutti i processi tra cui il nipote.

> 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

Conclusione

Ho notato in questo esempio PID e PGID sono uguali (28957).
Questo è il motivo per cui ho inizialmente pensato kill -- -$PID era sufficiente. Ma nel caso il processo è deporre le uova all'interno di un Makefile ID processo è diverso da quello ID gruppo .

Credo che kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) è il miglior trucco semplice per uccidere un albero intero processo quando viene chiamato da un diverso ID gruppo (un altro albero di processo).

pkill -TERM -P 27888

Questo ucciderà tutti i processi che hanno il 27888 ID processo padre.

O, più robusto:

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

che pianificazione uccidendo 33 secondi più tardi e gentilmente chiedere processi per terminare.

questa risposta per terminare tutti i discendenti.

Per uccidere un albero processo ricorsivo, uso 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 $@

rkill comando da pslist pacchetto invia dato segnale (o SIGTERM di default) per processo specificato e tutti i suoi discendenti:

rkill [-SIG] pid/name...

La risposta di Brad è quello che io consiglierei di troppo, tranne che si può fare a meno awk del tutto, se si utilizza l'opzione --ppid a ps.

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

se si sa passare il PID del processo genitore, ecco uno script di shell che dovrebbe funzionare:

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

Io uso un po bit versione modificata di un metodo descritto qui: https://stackoverflow.com/a/5311362/563175

Quindi sembra che:

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

dove 24901 è il PID del genitore.

Sembra piuttosto brutto, ma non si tratta di lavoro perfettamente.

Versione modificata della risposta di 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

Non posso commentare (reputazione insufficiente), quindi sono costretto ad aggiungerne uno nuovo risposta, anche se questa non è realmente una risposta.

C'è un piccolo problema con la risposta altrimenti molto gentile e approfondita data da @olibre il 28 febbraio.L'uscita di ps opgid= $PID conterrà spazi iniziali per un PID inferiore a cinque cifre perché ps sta giustificando la colonna (allinea i numeri a destra).All'interno dell'intera riga di comando, ciò risulta in un segno negativo, seguito da spazi, seguito dal PID del gruppo.La soluzione semplice è collegare il tubo ps A tr per rimuovere gli spazi:

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

Per aggiungere alla risposta di Norman Ramsey, può valere la pena guardare in setsid se si desidera creare un gruppo di processi.
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html

  

La funzione setsid () deve creare un   nuova sessione, se il processo chiamante è   Non un leader del gruppo processo. Su   restituire il processo chiamante deve essere   il leader della sessione di questa nuova   sessione, sarà il gruppo di processi   leader di un nuovo gruppo di processi, e   non avrà terminale di controllo.   Il gruppo ID del processo della vocazione   processo è impostata uguale alla   ID di processo del processo chiamante. Il   processo chiamante deve essere l'unico   processo nel nuovo gruppo processo e   l'unico processo nella nuova sessione.

Il che prendo a significare che è possibile creare un gruppo dal processo di partenza. Ho usato questo in php in modo da essere in grado di uccidere un albero intero processo dopo l'avvio di esso.

Questa può essere una cattiva idea. Sarei interessato a commenti.

del ysth commento

kill -- -PGID
  

invece di dare un numero di processo, dare la negazione del gruppo   numero. Come al solito con quasi tutti i comandi, se si vuole un argomento normale che   inizia con - non essere interpretati come un interruttore, precedere con --

La seguente funzione shell è simile a molte delle altre risposte, ma funziona sia su Linux e BSD (OS X, ecc) senza dipendenze esterne come 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
}

E 'super facile da fare questo con Python usando psutil . Basta installare psutil con pip e poi si dispone di una suite completa di strumenti di manipolazione del processo:

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

In base a risposta di Zhigang, questo evita di auto-omicidio:

init_killtree() {
    local pid=$1 child

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

Se si vuole uccidere un processo per nome:

killall -9 -g someprocessname

o

pgrep someprocessname | xargs pkill -9 -g

Questa è la mia versione di uccidere tutti i processi figli che utilizzano script bash. Non usa la ricorsione e dipende dal comando pgrep.

Usa

killtree.sh PID SIGNAL

Contenuto del 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//,/ }

Ecco una variazione della risposta di @ Zhigang, che fa a meno AWK, contando solo sulle possibilità di analisi native di Bash:

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

Sembra funzionare bene su Mac e Linux. In situazioni in cui non si può contare sul fatto di poter gestire i gruppi di processo - come quando la scrittura di script per testare un pezzo di software che deve essere costruito in più ambienti -. Questa tecnica tree-walking è sicuramente utile

Grazie per la tua saggezza, gente. Il mio script stava lasciando alcuni processi figlio in uscita e la negazione tip ha reso le cose più facili. Ho scritto questa funzione per essere utilizzato in altri script, se necessario:

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

Saluti.

Probabilmente è meglio uccidere il genitore prima dei figli;altrimenti il ​​genitore potrebbe probabilmente generare nuovamente nuovi figli prima di essere ucciso lui stesso.Questi sopravviveranno all'uccisione.

La mia versione di ps è diversa da quella sopra;forse troppo vecchio, quindi lo strano grepping...

Usare uno script di shell invece di una funzione di shell presenta molti vantaggi...

Tuttavia, è fondamentalmente un'idea di Zhigang


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

Il seguente è stato testato su FreeBSD, Linux e MacOS X e dipende solo pgrep e uccidere (il ps -o versioni non funzionano sotto BSD). Primo argomento è pid madre di cui i bambini devono essere terminato. secondo argomento è un valore booleano per determinare se il pid genitore deve essere terminata anche.

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

Questo invierà SIGTERM a qualsiasi processo figlio / nipote all'interno di uno script di shell e se SIGTERM non riesce, sarà attendere 10 secondi e quindi inviare uccidere.


precedente risposta:

Di seguito funziona anche, ma ucciderà la shell stessa su BSD.

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

I sviluppare la soluzione di Zhigang, xyuri e solidsneck ulteriormente:

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

Questa versione sarà evitare di uccidere la sua ascendenza -. Che provoca un flusso di processi figlio nelle soluzioni precedenti

I processi sono correttamente prima nell'elenco viene determinato, in modo che nessun nuovi bambini vengono creati o scompaiono.

Dopo essere stato ucciso, i posti di lavoro devono essere fermati continuato a scomparire dal sistema.

Old domanda, lo so, ma tutte le risposte sembrano continuare ad invocare ps, che non mi piace.

Questa soluzione awk-based non richiede ricorsione e chiama solo ps volta.

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

o su una singola linea:

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

In sostanza l'idea è che noi costruiamo una matrice (a) del genitore:. Elementi figlio, quindi anello intorno la matrice trovare i bambini per i nostri genitori corrispondenti, aggiungendoli alla nostra lista genitori (p) come andiamo

Se non si vuole uccidere il processo di livello superiore, quindi fare

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

poco prima della linea di sistema () sarebbe rimuoverla dal set di uccidere.

Tenete a mente che v'è una condizione di competizione qui, ma questo è vero (per quanto posso vedere) di tutte le soluzioni. Fa quello che mi serviva perché lo script ho bisogno per non crea un sacco di bambini di breve durata.

Un esercizio per il lettore potrebbe essere quella di rendere un loop 2-pass: dopo il primo passaggio, inviare SIGSTOP a tutti i processi nella lista p, quindi ciclo per eseguire ps nuovo e dopo il secondo passaggio inviare SIGTERM, poi SIGCONT . Se non si cura di belle finali poi secondo passaggio potrebbe essere solo SIGKILL, suppongo.

se avete pstree e perl sul vostro sistema, potete provare questo:

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

Se si conosce il PID della cosa si vuole uccidere, di solito si può andare dalla id di sessione, e tutto nella stessa sessione. Avevo doppio controllo, ma ho usato questo per gli script a partire rsyncs in cicli che voglio morire, e non iniziare un altro (a causa del loop) come sarebbe se avevo appena killall'd rsync.

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

Se non si conosce il PID si può ancora nidificano più

kill $(ps -o pid= -s $(ps -o sess --no-heading --pid $(pgrep rsync )))
ps -o pid= --ppid $PPID | xargs kill -9 

In sh i lavori comando elencherà i processi in background. In alcuni casi potrebbe essere migliore di uccidere il più recente processo di prima, ad esempio, quello più vecchio creato un socket condiviso. In tali casi ordinare i PIDs in ordine inverso. A volte si vuole attendere momento per i lavori di scrivere qualcosa su disco o cose del genere prima di smettere.

E non uccidere se non si deve!

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

Uccidere processo figlio in script di shell:

Molte volte abbiamo bisogno di uccidere processo figlio che sono impiccato o il blocco per qualche motivo. per esempio. problema di connessione FTP.

Ci sono due approcci,

1) Per creare nuovo genitore separato per ogni bambino che monitorerà e uccidere processo figlio una volta timeout raggiunto.

Crea test.sh come segue,

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

e guardare processi che stanno avendo nome 'test' in altro terminale tramite comando seguente.

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

Sopra script creerà 4 nuovi processi figli ei loro genitori. Ogni processo figlio avrà una durata di 10sec. Ma una volta che il timeout di 5 sec portata, appenderci rispettivi processi genitore uccideranno quelle del bambino. Così bambino non sarà in grado di completare l'esecuzione (10sec). Giocare intorno a quei tempi (interruttore 10 e 5) per vedere un altro comportamento. In tal caso bambino si concluderà esecuzione in 5 secondi prima che raggiunga il timeout di 10 sec.

2) Lasciare che il monitor del padre corrente e uccidere processo figlio una volta timeout raggiunto. Questo non creerà genitore separato per monitorare ogni bambino. Inoltre è possibile gestire tutti i processi figli correttamente all'interno stesso genitore.

Crea test.sh come segue,

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

e guardare processi che stanno avendo nome 'test' in altro terminale tramite comando seguente.

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

Sopra script creerà 4 nuovi processi figli. Abbiamo memorizzato PID di tutti processo figlio e loop su di loro per controllare se sono sono finiti la loro esecuzione o ancora in esecuzione. L'esecuzione processo bambino fino a tempo CMD_TIME. Ma se CNT_TIME_OUT timeout raggiungere, tutti i bambini avranno ucciso dal processo genitore. È possibile passare i tempi e giocare con script per vedere il comportamento. Uno svantaggio di questo approccio è che usa gruppo id per l'uccisione di tutti i albero bambino. Ma processo genitore stesso appartiene allo stesso gruppo così sarà anche ottenere ucciso.

Potrebbe essere necessario assegnare altri id gruppo di processo principale, se non si vuole genitore di essere ucciso.

Maggiori dettagli possono essere trovati qui,

Uccidere processo figlio in script di shell

Questo script funziona anche:

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

So che è vecchio, ma che è la soluzione migliore che ho trovato:

killtree() { 
    for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
        echo Terminating: $p 
        kill $p
    done
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top