¿Cuál es la mejor manera de enviar una señal a todos los miembros de un grupo de proceso?

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

  •  23-08-2019
  •  | 
  •  

Pregunta

Quiero matar un árbol de procesos completo.¿Cuál es la mejor manera de hacer esto utilizando lenguajes de secuencias de comandos comunes?Estoy buscando una solución sencilla.

¿Fue útil?

Solución

No se dice si el árbol se quiere matar es un único grupo de procesos. (Esto es a menudo el caso si el árbol es el resultado de que se bifurcan desde un inicio del servidor o una línea de comandos shell.) Usted puede descubrir grupos de proceso usando ps GNU de la siguiente manera:

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

Si se trata de un grupo de procesos se quiere matar, sólo tiene que utilizar el comando kill(1) pero en lugar de lo que le da un número de proceso, darle la negación del número de grupo. Por ejemplo, para matar todos los procesos en el grupo 5112, utilice kill -TERM -- -5112.

Otros consejos

Mata a todos los procesos pertenecientes a la misma árbol de procesos usando el Process Group ID (PGID)

  • kill -- -$PGID señal de uso predeterminado (TERM = 15)
  • kill -9 -$PGID Utilice el KILL de señal (9)

Puede recuperar el PGID de cualquier Proceso Id (PID) de la misma árbol de procesos

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

tángara y Speakus para las contribuciones en los espacios restantes $PID y compatibilidad OSX.

Explicación

  • kill -9 -"$PGID" => Enviar señal 9 (KILL) a todos los niños y nieto ...
  • PGID=$(ps opgid= "$PID") => Recuperar el Proceso-Group-ID de cualquier Proceso Id del árbol, no sólo la em> Proceso < -Padre-ID . Una variación de ps opgid= $PID es ps -o pgid --no-headers $PID donde pgid puede ser sustituido por pgrp . Pero
    :
    • ps insertos espacios líder cuando PID es menos de cinco dígitos y alineado a la derecha como notado por tanager . Se puede utilizar:
      PGID=$(ps opgid= "$PID" | tr -d ' ')
    • ps desde 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 de los dígitos sucesivos solamente (no se imprime espacios o encabezados alfabéticos).

Otras líneas de 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)

Limitación

  • 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 todo el árbol de la matanza.
  • Por lo tanto, asegúrese de ejecutar el comando utilizando un proceso que tiene un diferente Proceso-Group-ID .

Es una larga 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 usando 'y'

> ./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 mata 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 kill -- -$PGID comando mata 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

Me he dado cuenta en este ejemplo PID y PGID son iguales (28957).
Es por esto que originalmente pensé kill -- -$PID era suficiente. Pero en el caso de que el proceso se desovar dentro de un Makefile el ID de proceso es diferente de la ID de grupo .

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

pkill -TERM -P 27888

Esto matará a todos los procesos que tienen el 27888 ID de proceso principal.

O más robusto:

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

qué horario matando a 33 segundos más tarde y pedir educadamente a los procesos de interrumpir.

esta respuesta para la terminación de todos los descendientes.

Para matar a un árbol de procesos de forma recursiva, el 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 de pslist paquete envía da señal (o SIGTERM por defecto) para proceso especificado y todos sus descendientes:

rkill [-SIG] pid/name...

La respuesta de Brad es lo que me gustaría recomendar también, excepto que usted puede acabar con awk por completo si se utiliza la opción --ppid a ps.

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

Si conoce a pasar el pid del proceso padre, aquí hay un script de shell que debería funcionar:

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

Yo uso una pequeña versión modificada poco de un método descrito aquí: https://stackoverflow.com/a/5311362/563175

Así que parece que:

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

donde 24901 es PID de los padres.

Se ve bastante feo, pero hace su trabajo perfectamente.

Versión modificada de la respuesta de 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

No puedo comentar (no tengo suficiente reputación), así que me veo obligado a agregar un nuevo respuesta, aunque esto no es realmente una respuesta.

Hay un pequeño problema con la respuesta, por lo demás muy agradable y completa, dada por @olibre el 28 de febrero.La salida de ps opgid= $PID contendrá espacios iniciales para un PID de menos de cinco dígitos porque ps está justificando la columna (alinee los números a la derecha).Dentro de toda la línea de comando, esto da como resultado un signo negativo, seguido de espacios y seguido del PID del grupo.La solución simple es canalizar ps a tr para eliminar espacios:

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

Para añadir a la respuesta de Norman Ramsey, puede ser digno de mirar en setsid si desea crear un grupo de procesos.
http://pubs.opengroup.org/onlinepubs/009695399/functions/setsid.html

  

La función setsid () creará una   nueva sesión, si el proceso de llamada es   no un líder de grupo de procesos. Sobre   devolver el proceso de llamada será   el líder de la sesión de este nuevo   sesión, será el grupo de procesos   líder de un nuevo grupo de procesos, y   no tendrá terminal de control.   El ID de grupo de proceso de la llamada   proceso se fijará igual a la   ID de proceso del proceso de llamada. los   proceso llamando será el único   proceso en el nuevo grupo de proceso y   el único proceso en la nueva sesión.

Lo que tomo en el sentido de que se puede crear un grupo del proceso de arranque. He utilizado este en php con el fin de ser capaz de matar un árbol todo el proceso después de comenzar la misma.

Esto puede ser una mala idea. Yo estaría interesado en los comentarios.

comentario de ysth

kill -- -PGID
  

en lugar de lo que le da un número de proceso, darle la negación del grupo   número. Como es habitual en casi cualquier comando, si quieres un argumento común que emplean   comienza con una - que no deben interpretarse como un interruptor, precedido de --

La siguiente función de cáscara es similar a muchas de las otras respuestas, pero funciona tanto en Linux y BSD (OS X, etc.) sin dependencias externas como 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
}

Es muy fácil de hacer esto con Python usando psutil . Sólo tiene que instalar psutil con PIP y entonces usted tiene un conjunto completo de herramientas de manipulación de proceso:

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

Sobre la base de la respuesta de Zhigang, esto evita la auto-asesinato:

init_killtree() {
    local pid=$1 child

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

Si quieres matar a un proceso por el nombre:

killall -9 -g someprocessname

o

pgrep someprocessname | xargs pkill -9 -g

Esta es mi versión de matar a todos los procesos hijos utilizando escritura del golpe. No utiliza la recursividad y depende de comandos pgrep.

Uso

killtree.sh PID SIGNAL

El contenido de 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//,/ }

Esta es una variación de la respuesta de @ Zhigang, que prescinde de AWK, basándose únicamente en las posibilidades de análisis nativos de 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"
}

Parece que funciona bien tanto en Mac y Linux. En situaciones en las que no se puede confiar en ser capaces de gestionar grupos de proceso - como al escribir guiones para probar una pieza de software que debe ser construido en múltiples entornos -. Esta técnica de árbol caminar es definitivamente útil

Gracias por su sabiduría, amigos. Mi script se marchaba algunos procesos hijo a la salida y el negación punta ha facilitado las cosas. Escribí esta función para utilizar en otras secuencias de comandos si es necesario:

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

Saludos.

Probablemente es mejor matar a los padres delante de los hijos; de lo contrario el padre puede probable desovar nuevos niños de nuevo antes de que él mismo se mató. Estos sobrevivirán a la muerte.

Mi versión de ps es diferente de la anterior; tal vez demasiado viejo, por lo tanto, la extraña grepping ...

Para usar un script de shell en lugar de una función Shell tiene muchas ventajas ...

Sin embargo, es básicamente zhigangs idea


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

La siguiente ha sido probado en FreeBSD, Linux y MacOS X y sólo depende de pgrep y matar (la ps -o versiones no funcionan bajo BSD). El primer argumento es el pid matriz de la que los niños tienen que ser terminado. segundo argumento es un valor booleano para determinar si el pid padre tiene que ser terminada también.

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

Esto enviará SIGTERM a cualquier proceso hijo / nieto dentro de un script de shell y si SIGTERM no tiene éxito, se va a esperar 10 segundos y luego enviar matanza.


A principios de respuesta:

Lo siguiente también funciona, pero puede matar el intérprete sí en 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 desarrollar la solución de Zhigang, xyuri y solidsneck además:

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

Esta versión evitar la muerte de sus ancestros -. Lo que provoca una inundación de procesos hijo en las soluciones anteriores

Los procesos están correctamente detenido antes de que se determina la lista de elementos secundarios, por lo que no hay niños nuevos se crean o desaparecen.

Después de haber sido matado, los trabajos detenidos tienen que ser continuado a desaparecer del sistema.

vieja pregunta, lo sé, pero todas las respuestas parecen seguir llamando ps, lo que no me gusta.

Esta solución basada en awk no requiere la repetición y sólo llama una vez ps.

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 en una sola línea:

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

Básicamente, la idea es que construimos una matriz (a) del padre:. Entradas secundarias, entonces bucle alrededor de la matriz de búsqueda de niños para los padres a juego, agregarlos a nuestra lista de los padres (p) a medida que avanzamos

Si no desea matar al proceso de nivel superior, a continuación, haciendo

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

justo antes de la línea del sistema () sería sacarlo de la serie de muertes.

Tenga en cuenta que existe una condición de carrera aquí, pero eso es cierto (por lo que puedo ver) de todas las soluciones. Se hace lo que necesitaba porque el guión lo necesitaba para no crear un montón de niños de corta duración.

Un ejercicio para el lector sería hacer que un bucle de 2 pasos: después de la primera pasada, enviar SIGSTOP a todos los procesos en la lista de p, entonces bucle para ejecutar ps nuevo y después de la segunda pasada enviar SIGTERM, entonces SIGCONT . Si no se preocupan por buenas terminaciones entonces segundo paso podría ser sólo SIGKILL, supongo.

Si usted tiene pstree y Perl en su sistema, puede intentar lo siguiente:

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

Si conoce el PID de la cosa que quiere matar, por lo general puede ir desde el identificador de sesión, y todo en la misma sesión. Me había doble control, pero he usado esto para las secuencias de comandos a partir rsyncs en bucles que quiero a morir, y no iniciar otro (debido al bucle) como lo haría si acabara de killall'd rsync.

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

Si usted no sabe el pid todavía se puede nido más

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

En los trabajos sh comando enumerará los procesos en segundo plano. En algunos casos, podría ser mejor para matar el proceso más reciente en primer lugar, por ejemplo, la más antigua crea un socket compartido. En esos casos ordenar los PIDs en orden inverso. A veces quieres que esperar momento para que los puestos de trabajo de escribir algo en el disco o cosas por el estilo antes de que paren.

Y no matar si no tiene que hacerlo!

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

Killing proceso hijo en escritura shell:

Muchos tiempo que necesitamos para matar proceso hijo que se colgaron o bloque por alguna razón. p.ej. edición de la conexión FTP.

Hay dos enfoques,

1) Para crear una nueva matriz diferente para cada hijo que monitoreará y matar proceso hijo una vez alcanzado el tiempo de espera.

Crea test.sh de la siguiente manera:

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

y ver procesos que están teniendo nombre como 'prueba' en otro terminal usando los siguientes comandos.

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

Por encima de script creará 4 nuevos procesos hijos y sus padres. Cada proceso hijo tendrá una duración de 10 segundos. Pero una vez que el tiempo de espera de 5 segundos alcance, arreglan sus respectivos procesos padre matarán a los del niño. Para que el niño no será capaz de completar la ejecución (10 seg). Juega un poco esos tiempos (switch 10 y 5) para ver otro comportamiento. En ese caso niño terminará la ejecución en 5 segundos antes de que llegue el tiempo de espera de 10 segundos.

2) Que el monitor primario actual y matar proceso hijo una vez alcanzado el tiempo de espera. Esto no creará matriz separada para monitorear cada niño. También se pueden gestionar todos los procesos hijos adecuadamente dentro de la misma matriz.

Crea test.sh de la siguiente manera:

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

y ver procesos que están teniendo nombre como 'prueba' en otro terminal usando los siguientes comandos.

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

Por encima de script creará 4 nuevos procesos hijos. Estamos almacenando los PID de todo proceso hijo y bucles sobre ellos para comprobar si se acaban su ejecución o aún en marcha. La ejecución proceso hijo hasta la hora CMD_TIME. Pero si CNT_TIME_OUT tiempo de espera alcanzar, todos los niños consiguen matado por proceso padre. Se puede cambiar el tiempo y jugar con la escritura para ver el comportamiento. Una desventaja de este método es que se utiliza la ID de grupo para matar a todos los niños del árbol. Pero proceso padre en sí pertenecen al mismo grupo por lo que también va a ser asesinado.

Es posible que tenga que asignar otro Identificación del grupo de proceso padre si no desea que los padres que se mató.

Más detalles se pueden encontrar aquí,

Killing proceso hijo en shell script

Este script también funciona:

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

Sé que es viejo, pero esa es la mejor solución que he encontrado:

killtree() { 
    for p in $(pstree -p $1 | grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*" | tac);do
        echo Terminating: $p 
        kill $p
    done
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top