¿Cómo se puede matar a todos los procesos de Linux que son mayores de cierta edad?

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

  •  08-06-2019
  •  | 
  •  

Pregunta

Tengo un problema con algunos zombis como los procesos que en un determinado servidor que necesitan ser asesinadas cada ahora y entonces.Cómo puedo identificar los que han funcionado durante más de una hora o así?

¿Fue útil?

Solución

Si sólo necesita ser muerto:

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi

Si usted quiere ver lo que es coincidente

if [[ "$(uname)" = "Linux" ]];then killall -i --older-than 1h someprocessname;fi

El -i indicador mostrará sí/no para cada proceso partido.

Otros consejos

Encontré una respuesta que me funciona:

advertencia:esta va a encontrar y matar largo de la ejecución de los procesos

ps -eo uid,pid,etime | egrep '^ *user-id' | egrep ' ([0-9]+-)?([0-9]{2}:?){3}' | awk '{print $2}' | xargs -I{} kill {}

(Donde -id de usuario es de un usuario específico de IDENTIFICACIÓN con los procesos de larga duración.)

La segunda expresión regular coincide con el tiempo de que dispone de una opción de días figura, seguido por una hora, el minuto y el segundo componente, y así es en menos de una hora de duración.

Para cualquier cosa de más de un día,

ps aux

te dará la respuesta, pero desciende a día de precisión que podría no ser tan útil.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   7200   308 ?        Ss   Jun22   0:02 init [5]
root         2  0.0  0.0      0     0 ?        S    Jun22   0:02 [migration/0]
root         3  0.0  0.0      0     0 ?        SN   Jun22   0:18 [ksoftirqd/0]
root         4  0.0  0.0      0     0 ?        S    Jun22   0:00 [watchdog/0]

Si estás en linux u otro sistema con el sistema de archivos /proc, En este ejemplo, sólo se puede ver que el proceso 1 ha estado funcionando desde el 22 de junio, pero no se indica el momento en que se inició.

stat /proc/<pid>

le dará una respuesta más precisa.Por ejemplo, he aquí una indicación de la hora exacta para el proceso 1, que ps solo muestra como Jun22:

ohm ~$ stat /proc/1
  File: `/proc/1'
  Size: 0               Blocks: 0          IO Block: 4096   directory
Device: 3h/3d   Inode: 65538       Links: 5
Access: (0555/dr-xr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2008-06-22 15:37:44.347627750 -0700
Modify: 2008-06-22 15:37:44.347627750 -0700
Change: 2008-06-22 15:37:44.347627750 -0700

De esta manera usted puede obtener la lista de las diez más antiguas de los procesos de:

ps -elf | sort -r -k12 | head -n 10

Jodie C y otros han señalado que killall -i puede ser utilizado, lo cual está bien si desea utilizar el nombre del proceso a matar.Pero si quieres matar por los mismos parámetros que pgrep -f, usted necesita usar algo como lo siguiente, usando puro bash y el /proc el sistema de ficheros.

#!/bin/sh                                                                                                                                               

max_age=120 # (seconds)                                                                                                                                 
naughty="$(pgrep -f offlineimap)"                                                                                                                       
if [[ -n "$naughty" ]]; then # naughty is running                                                                                                       
  age_in_seconds=$(echo "$(date +%s) - $(stat -c %X /proc/$naughty)" | bc)                                                                              
  if [[ "$age_in_seconds" -ge "$max_age" ]]; then # naughty is too old!                                                                                 
    kill -s 9 "$naughty"                                                                                                                                
  fi                                                                                                                                                    
fi     

Esto le permite encontrar y matar a procesos mayores de max_age de segundos, usando el completo nombre de proceso;es decir, el proceso denominado /usr/bin/python2 offlineimap pueden ser asesinados por la referencia a "offlineimap", mientras que el killall las soluciones que aquí se presenta sólo el trabajo en la cadena "python2".

Perl del Proc::ProcessTable hará el truco:http://search.cpan.org/dist/Proc-ProcessTable/

Se puede instalar en debian o ubuntu con sudo apt-get install libproc-processtable-perl

Aquí es de una sola línea:

perl -MProc::ProcessTable -Mstrict -w -e 'my $anHourAgo = time-60*60; my $t = new Proc::ProcessTable;foreach my $p ( @{$t->table} ) { if ($p->start() < $anHourAgo) { print $p->pid, "\n" } }'

O, más formateados, poner esto en un archivo llamado process.pl:

#!/usr/bin/perl -w
use strict;
use Proc::ProcessTable;
my $anHourAgo = time-60*60;
my $t = new Proc::ProcessTable;
foreach my $p ( @{$t->table} ) {
    if ($p->start() < $anHourAgo) {
        print $p->pid, "\n";
    }
}

a continuación, ejecute perl process.pl

Esto le da más versatilidad y 1 de segunda resolución sobre la hora de inicio.

Puede utilizar bc para unir las dos comandos en la muchedumbre de la respuesta y obtener cuántos segundos ellapsed desde el inicio del proceso:

echo `date +%s` - `stat -t /proc/<pid> | awk '{print $14}'` | bc

editar:

De aburrimiento mientras se espera por largos procesos a ejecutar, esto es lo que salió después de unos minutos de tocar el violín:

#file: sincetime
#!/bin/bash
init=`stat -t /proc/$1 | awk '{print $14}'`
curr=`date +%s`
seconds=`echo $curr - $init| bc`
name=`cat /proc/$1/cmdline`
echo $name $seconds

Si pone esto en su ruta y la llamada de esta manera:sincetime

se imprimirá el proceso de cmdline y segundos desde que se inició.Usted puede también poner esto en tu camino:

#file: greptime
#!/bin/bash
pidlist=`ps ax | grep -i -E $1 | grep -v grep | awk '{print $1}' | grep -v PID | xargs echo`
for pid in $pidlist; do
    sincetime $pid
done

Y que si se ejecuta:

greptime <pattern>

donde los patrones es una cadena o de expresiones regulares extendidas, que imprimirá todos los procesos que coincidan con este patrón, y los segundos desde que comenzaron.:)

hacer un ps -aef.esto le mostrará el tiempo en el que el proceso iniciado.A continuación, utilizando el date comando de encontrar el momento actual.Calcular la diferencia entre los dos para encontrar la edad de el proceso.

Yo hice algo similar a la aceptación de responder, pero de manera ligeramente diferente, ya que quiero partido basado en el nombre del proceso y basado en el mal funcionamiento de proceso de más de 100 segundos

kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')

stat -t /proc/<pid> | awk '{print $14}'

para obtener la hora de inicio del proceso en segundos desde la época.Comparar con la actual tiempo (date +%s) para obtener la edad actual del proceso.

El uso de ps es el camino correcto.Ya he hecho algo similar antes, pero no tengo la fuente a la mano.En general - ps tiene una opción para decirle que los campos a mostrar y por la que desea ordenar.Usted puede ordenar la salida por tiempo de funcionamiento, grep, el proceso que se desea y luego matarlo.

HTH

En caso de que alguien necesita esta en C:, puede usar readproc.h y libproc:

#include <proc/readproc.h>
#include <proc/sysinfo.h>

float
pid_age(pid_t pid)
{
        proc_t proc_info;
        int seconds_since_boot = uptime(0,0);
        if (!get_proc_stats(pid, &proc_info)) {
                return 0.0;
        }

        // readproc.h comment lies about what proc_t.start_time is. It's
        // actually expressed in Hertz ticks since boot

        int  seconds_since_1970 = time(NULL);
        int time_of_boot = seconds_since_1970 - seconds_since_boot;
        long  t = seconds_since_boot - (unsigned long)(proc_info.start_time / Hertz);

        int delta = t;
        float days = ((float) delta / (float)(60*60*24));
        return days;
}

Encontré en algún lugar..el pensamiento es simple y útil

Puede utilizar el comando crontab directamente ,

* * * * * ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F
+[13]; kill 9, $F[3] if ($h > 1);'

o, podemos escribir la secuencia de comandos de shell

#!/bin/sh
# longprockill.sh
ps -lf | grep "user" |  perl -ane '($h,$m,$s) = split /:/,$F[13]; kill
+ 9, $F[3] if ($h > 1);'

Y lo llaman crontab como así,

* * * * * longprockill.sh

Mi versión de sincetime arriba por @Rafael S.Calsaverini :

#!/bin/bash
ps --no-headers -o etimes,args "$1"

Esto invierte la salida de campos:tiempo transcurrido en primer lugar, comando completo, incluyendo los argumentos de la segunda.Este es el método preferido debido a que el comando completo puede contener espacios.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top