ver usuarios users useradd tipo secundario reservados qué que para los listar grupo generalmente están encuentran ejemplos directorio comando borrar linux shell process signals

usuarios - useradd linux ejemplos



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

Aquí hay una variación de la respuesta de @zhigang que no tiene AWK, confiando solo en las posibilidades de análisis nativas 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 funcionar bien tanto en Mac como en Linux. En situaciones en las que no puede confiar en la capacidad de administrar grupos de procesos, como cuando se escriben scripts para probar una pieza de software que debe estar integrada en múltiples entornos, esta técnica de caminar por el árbol es definitivamente útil.

Quiero matar todo un árbol de proceso. ¿Cuál es la mejor manera de hacerlo utilizando cualquier lenguaje de scripting común? Estoy buscando una solución simple.


Basado en la respuesta de zhigang, esto evita la matanza:

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


Desarrollé la solución de zhigang, xyuri y solidsneck má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á matar su ascendencia, lo que provoca una avalancha de procesos secundarios en las soluciones anteriores.

Los procesos se detienen correctamente antes de que se determine la lista secundaria, de modo que no se creen ni desaparezcan nuevos hijos.

Después de ser eliminados, los trabajos detenidos deben continuar desapareciendo del sistema.


Elimine todos los procesos que pertenecen al mismo árbol de procesos utilizando la ID de grupo de procesos ( PGID )

  • kill -- -$PGID Usa la señal por defecto ( TERM = 15)
  • kill -9 -$PGID Usa la señal KILL (9)

Puede recuperar el PGID de cualquier ID de proceso ( PID ) del mismo árbol de proceso

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

Un agradecimiento especial a tanager y Speakus por las contribuciones en los espacios restantes de $PID y la compatibilidad con OSX.

Explicación

  • kill -9 -"$PGID" => Envíe la señal 9 ( KILL ) a todos los hijos y nietos ...
  • PGID=$(ps opgid= "$PID") => Recupere la ID de grupo de proceso de cualquier ID de proceso del árbol, no solo la ID de padre de proceso . Una variación de ps opgid= $PID es ps -o pgid --no-headers $PID donde pgid puede reemplazarse por pgrp .
    Pero:
    • ps inserta espacios PID cuando PID tiene menos de cinco dígitos y está alineado a la derecha según lo notado por tanager . Puedes usar:
      PGID=$(ps opgid= "$PID" | tr -d '' '')
    • ps desde OSX siempre imprime el encabezado, por Speakus tanto, Speakus propone:
      PGID="$( ps -o pgid "$PID" | grep [0-9] | tr -d '' '' )"
  • grep -o [0-9]* imprime solo dígitos sucesivos (no imprime espacios ni encabezados alfabéticos).

Lineas de comando adicionales

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

  • Como lo notaron davide y Hubert Kario , cuando se invoca a kill por un proceso que pertenece al mismo árbol, kill riesgos de suicidarse antes de terminar con la matanza del árbol completo.
  • Por lo tanto, asegúrese de ejecutar el comando utilizando un proceso que tenga un ID de grupo de procesos diferente.

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

Ejecute el árbol de procesos en segundo plano usando ''&''

> ./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 comando kill -- -$PGID mata todos los procesos, incluido 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

PGID en este ejemplo, PID y PGID son iguales ( 28957 ).
Es por eso que originalmente pensé que kill -- -$PID era suficiente. Pero en el caso de que el proceso se genere dentro de un Makefile la ID del proceso es diferente de la ID del grupo .

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


En sh, el comando de trabajos listará los procesos en segundo plano. En algunos casos, podría ser mejor eliminar primero el proceso más nuevo, por ejemplo, el anterior creó un socket compartido. En esos casos, ordene los PID en orden inverso. A veces desea esperar un momento para que los trabajos escriban algo en el disco o cosas así antes de que se detengan.

¡Y no mates si no tienes que hacerlo!

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


Es muy fácil hacer esto con python usando psutil . Simplemente instale psutil con pip y luego tendrá un conjunto completo de herramientas de manipulación de procesos:

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


Esta es mi versión de matar todos los procesos secundarios utilizando el script bash. No utiliza recursión y depende del comando pgrep.

Utilizar

killtree.sh PID SIGNAL

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


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


Gracias por su sabiduría, amigos. Mi script estaba dejando algunos procesos secundarios al salir y la sugerencia de negación facilitó las cosas. Escribí esta función para ser usada en otros scripts 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 }

Aclamaciones.


Inspirado por el comentario de ysth.

kill -- -PGID

en lugar de darle un número de proceso, denle la negación del número de grupo. Como es habitual con casi cualquier comando, si desea que un argumento normal que comience con un - para que no se interprete como un interruptor, debe precederlo con --


La respuesta de brad es lo que recomendaría también, excepto que puedes eliminar awk completo si usas la opción --ppid para ps .

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


La siguiente función de shell es similar a muchas de las otras respuestas, pero funciona tanto en Linux como en 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 }


Lo siguiente ha sido probado en FreeBSD, Linux y MacOS X y solo depende de pgrep y kill (las versiones ps -o no funcionan en BSD). El primer argumento es el pid principal de los cuales los hijos deben ser terminados. El segundo argumento es un valor booleano para determinar si el pid principal debe terminarse 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, esperará 10 segundos y luego enviará kill.

Respuesta anterior:

Lo siguiente también funciona pero matará al shell 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


Matar proceso hijo en shell script:

Muchas veces necesitamos matar el proceso hijo que está colgado o bloqueado por alguna razón. p.ej. Problema de conexión FTP.

Hay dos enfoques,

1) Para crear un nuevo padre separado para cada hijo que monitoreará y eliminará el proceso hijo una vez que se alcance el tiempo de espera.

Crear 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 observe los procesos que tienen nombre como ''prueba'' en otra terminal usando el siguiente comando.

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

El script anterior creará 4 nuevos procesos secundarios y sus padres. Cada proceso hijo se ejecutará durante 10 s. Pero una vez que se agote el tiempo de espera de 5 segundos, sus procesos padres respectivos matarán a esos niños. Así que el niño no podrá completar la ejecución (10 s). Juegue alrededor de esos tiempos (interruptor 10 y 5) para ver otro comportamiento. En ese caso, el niño terminará la ejecución en 5 segundos antes de que llegue a un tiempo de espera de 10 segundos.

2) Deje que el padre actual supervise y mate el proceso una vez que se alcance el tiempo de espera. Esto no creará padres separados para monitorear a cada niño. También puede administrar todos los procesos secundarios correctamente dentro del mismo padre.

Crear 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 observe los procesos que tienen nombre como ''prueba'' en otra terminal usando el siguiente comando.

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

El script anterior creará 4 nuevos procesos secundarios. Estamos almacenando los pids de todos los procesos secundarios y repasándolos en bucle para verificar si han terminado su ejecución o si todavía se están ejecutando. El proceso hijo se ejecutará hasta el tiempo CMD_TIME. Pero si CNT_TIME_OUT alcanza el tiempo de espera, todos los niños serán asesinados por el proceso principal. Puedes cambiar el tiempo y jugar con el script para ver el comportamiento. Un inconveniente de este enfoque es que utiliza la identificación de grupo para matar a todos los árboles secundarios. Pero el proceso de los padres pertenece al mismo grupo, por lo que también será asesinado.

Es posible que deba asignar otra ID de grupo al proceso principal si no desea que se elimine la función principal.

Más detalles se pueden encontrar aquí,

Matar proceso hijo en shell script


No dices si el árbol que quieres matar es un solo grupo de procesos. (Este suele ser el caso si el árbol es el resultado de forking desde un inicio de servidor o una línea de comando de shell). Puede descubrir grupos de procesos usando GNU ps de la siguiente manera:

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

Si desea eliminar un grupo de procesos, solo use el comando kill(1) pero en lugar de darle un número de proceso, niegue el número de grupo. Por ejemplo, para eliminar todos los procesos del grupo 5112, use kill -TERM -- -5112 .


No puedo comentar (no tengo suficiente reputación), por lo que me veo obligado a agregar una nueva respuesta , aunque esta no sea realmente una respuesta.

Hay un pequeño problema con la respuesta muy agradable y completa de @olibre el 28 de febrero. La salida de ps opgid= $PID contendrá espacios ps opgid= $PID para un PID más corto que cinco dígitos porque ps está justificando la columna (alinear correctamente números). Dentro de la línea de comando completa, esto resulta en un signo negativo, seguido de espacio (s), seguido del PID de grupo. Una solución simple es canalizar ps a tr para eliminar espacios:

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


Para agregar a la respuesta de Norman Ramsey, puede valer la pena ver 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 no es un líder de grupo de proceso. Al regresar, el proceso de llamada será el líder de la sesión de esta nueva sesión, será el líder del grupo de proceso de un nuevo grupo de proceso y no tendrá terminal de control. El ID de grupo de proceso del proceso de llamada se establecerá igual al ID de proceso del proceso de llamada. El proceso de llamada será el único proceso en el nuevo grupo de procesos y el único proceso en la nueva sesión.

Lo que entiendo es que puedes crear un grupo desde el proceso de inicio. Utilicé esto en PHP para poder matar todo un árbol de procesos después de iniciarlo.

Esto puede ser una mala idea Me interesaría hacer comentarios.


Para matar un árbol de proceso de forma recursiva, use 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 $@


Probablemente es mejor matar a los padres antes que a los niños; de lo contrario, es probable que el padre vuelva a engendrar nuevos hijos antes de que él mismo se mate. Estos sobrevivirán a la matanza.

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

Usar un script de shell en lugar de una función de shell tiene muchas ventajas ...

Sin embargo, es básicamente una idea zhigangs

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


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

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


Si conoce el pid de lo que quiere matar, normalmente puede ir desde el ID de sesión y todo en la misma sesión. Lo comprobé nuevamente, pero utilicé esto para los scripts que inician rsyncs en los bucles en los que quiero morir, y no en otro (debido al bucle) como lo haría si solo quisiera hacer killall''d rsync.

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

Si no conoces el pid todavía puedes anidar más.

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


Si quieres matar un proceso por nombre:

killall -9 -g someprocessname

o

pgrep someprocessname | xargs pkill -9 -g


Si sabe cómo 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


Si tiene pstree y perl en su sistema, puede intentar esto:

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


Utilizo un poco la versión modificada de un método descrito aquí: https://.com/a/5311362/563175

Así se ve así:

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

donde 24901 es el PID de los padres.

Parece bastante feo, pero funciona 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


Vieja pregunta, lo sé, pero todas las respuestas parecen seguir llamando ps, lo que no me gustó.

Esta solución basada en awk no requiere recursión y solo llama a ps una vez.

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 construyamos una matriz (a) de padres: entradas secundarias, luego recorramos la matriz encontrando hijos para nuestros padres correspondientes, agregándolos a nuestra lista de padres (p) a medida que avanzamos.

Si no quieres matar el proceso de nivel superior, hazlo

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

justo antes de que la línea del sistema () la eliminara del conjunto de eliminación.

Tenga en cuenta que hay una condición de carrera aquí, pero eso es cierto (por lo que puedo ver) de todas las soluciones. Hace lo que necesitaba porque el guión para el que lo necesitaba no crea muchos niños de corta duración.

Un ejercicio para el lector sería convertirlo en un bucle de 2 pases: después de la primera pasada, envíe SIGSTOP a todos los procesos en la lista p, luego haga un bucle para ejecutar ps otra vez y después de la segunda pasada envíe SIGTERM, luego SIGCONT. Si no te importan los buenos finales, el segundo paso podría ser SIGKILL, supongo.


rkill comando pslist paquete pslist envía la señal dada (o SIGTERM por defecto) al proceso especificado y a todos sus descendientes:

rkill [-SIG] pid/name...


pkill -TERM -P 27888

Esto eliminará todos los procesos que tengan el ID de proceso primario 27888.

O más robusto:

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

qué horario matan 33 segundos más tarde y cortésmente piden procesos para terminar.

Vea esta respuesta para terminar con todos los descendientes.


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