400 votos

La mejor manera de matar a todos los procesos hijos

Básicamente quiero matar a un árbol de procesos en general. ¿Cuál es la mejor manera de hacer esto utilizando cualquier lenguaje de scripting comunes. Estoy buscando una solución simple.

281voto

Norman Ramsey Puntos 115730

No dices si el árbol se quieren matar es un proceso único grupo. (Esto es a menudo el caso, si el árbol es el resultado de la bifurcación de un servidor de inicio o un shell de línea de comandos.) Usted puede descubrir grupos de procesos usando GNU ps como sigue:

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

Si se trata de un proceso de grupo que lo quieren matar, utiliza la kill(1) de comandos, pero en vez de dar un número de proceso, darle la negación de que el número de grupo. Por ejemplo, para matar cada proceso en grupo 5112, use kill -TERM -5112.

183voto

olibre Puntos 6069

kill -- -$PGID (donde $PGID es el Proceso-Group-ID)
kill -9 -$PGID

o la versión ultimate de usar cualquier ID de Proceso ($PID) del árbol:

kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) => Enviar TERM para el conjunto de árboles
kill -9 -$(ps -o pgid= $PID | grep -o [0-9]*) => Enviar KILL para el conjunto de árboles

Gracias tangara y Speakus por tus aportaciones sobre el resto de los espacios en $PID y compatibilidad con OSX.

Explicaciones:

  • kill -9 -"$PGID" => Enviar señal 9 (MATAR) a todos, hijo, nieto...
  • PGID=$(ps opgid= "$PID") => Recuperar el Proceso-Group-ID de cualquier Proceso de IDENTIFICACIÓN de los árboles, no sólo el Proceso de IDENTIFICACIÓN de los Padres. Una variación de ps opgid= $PID es ps -o pgid --no-headers $PID donde pgid puede ser reemplazada por pgrp.
    Pero:
    • ps inserta espacios cuando el PID está a menos de cinco dígitos y la derecha se alinea como notado por la tangara. Usted puede utilizar:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps de OSX siempre imprimir el encabezado, por lo tanto Speakus propone:
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d ' ' )"
  • grep -o [0-9]* impresiones sucesivas sólo dígitos (no se imprime espacios alfabética o encabezados).

Otros ejemplos:

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)

Limitaciones:

  • Como notado por davide y Hubert Kario, cuando kill es invocado por un proceso que pertenece al mismo árbol, kill riesgos para matar a sí mismo antes de terminar el árbol entero.
  • Por lo tanto, asegúrese de ejecutar el comando utilizando otro Proceso-Group-ID.

Largo de la historia

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

Ejecutar el árbol de procesos en segundo plano con '&'

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

El comando pkill -P $PID no matar al nieto:

> 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

El comando kill -- -$PGID matar a todos los procesos incluyendo el nieto.

> 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

Conclusión

Puedo notar en este ejemplo, PID y PGID son iguales (28957).
Esta es la razón por la que yo pensaba originalmente kill -- -$PID fue suficiente. Pero en el caso de que el proceso es spawn dentro de un Makefile el Proceso de IDENTIFICACIÓN es diferente de la de ID de Grupo.


Pienso kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) es el mejor truco sencillo para matar a todo un proceso de árbol cuando se llama desde un diferente ID de Grupo (otro proceso de árbol).

164voto

Onlyjob Puntos 1244
 pkill -TERM -P 27888
 

donde 27888 es el PID del padre.

O más robusto:

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

el programa que va matando a 33 segundos más tarde y pedir educadamente a los procesos de terminar.

99voto

zhigang Puntos 899

Para matar a un árbol de procesos de forma recursiva, utilice 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 $@
 

11voto

Kim Stebel Puntos 22873

La respuesta de brad es lo que yo recomiendo también, excepto que usted puede acabar con awk por completo si se utiliza la opción --ppid a ps.

para niño en $ (ps -o pid -ax --ppid $ PPID) hacer ....... hecho

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: