servicios - ver procesos de un usuario linux
¿Cómo matas a todos los procesos de Linux que tienen más de cierta edad? (13)
De esta manera puede obtener la lista de los diez procesos más antiguos:
ps -elf | sort -r -k12 | head -n 10
Tengo un problema con algunos procesos tipo zombie en un determinado servidor que deben ser eliminados de vez en cuando. ¿Cómo puedo identificar mejor a los que se han ejecutado durante más de una hora más o menos?
El uso de ps es el camino correcto. Ya hice algo similar antes, pero no tengo la fuente a mano. En general, ps tiene una opción para indicarle qué campos mostrar y ordenar. Puede ordenar el resultado por tiempo de ejecución, grep el proceso que desea y luego matarlo.
HTH
En caso de que alguien necesite esto 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é una respuesta que funciona para mí:
advertencia: esto encontrará y matará procesos de larga ejecución
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 el ID de un usuario específico con procesos de larga ejecución).
La segunda expresión regular coincide con la hora que tiene una cifra de días opcional, seguida de una hora, minutos y un segundo componente, y por lo tanto tiene al menos una hora de duración.
Hice algo similar a la respuesta aceptada, pero ligeramente diferente, ya que quiero hacer coincidir según el nombre del proceso y en función del mal proceso que se está ejecutando durante más de 100 segundos.
kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk ''{ if ($RN > 1 && $2 > 100) { print $1; }}'')
Jodie C y otros han señalado que se puede usar killall -i
, lo cual está bien si quieres usar el nombre del proceso para matar. Pero si quiere matar con los mismos parámetros que pgrep -f
, debe usar algo como lo siguiente, usando pure bash y el sistema de archivos /proc
.
#!/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 buscar y eliminar procesos anteriores a max_age
segundos utilizando el nombre completo del proceso ; es decir, el proceso llamado /usr/bin/python2 offlineimap
puede /usr/bin/python2 offlineimap
por referencia a "offlineimap", mientras que las soluciones de killall
presentadas aquí solo funcionarán en la cadena "python2".
Llegó a algún lado ... aunque es simple y útil
Puede usar el comando en crontab directamente,
* * * * * ps -lf | grep "user" | perl -ane ''($h,$m,$s) = split /:/,$F
+[13]; kill 9, $F[3] if ($h > 1);''
o, podemos escribirlo como script 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 llámalo crontab como tal,
* * * * * longprockill.sh
Para cualquier cosa anterior a un día,
ps aux
le dará la respuesta, pero se reduce a la precisión del día 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á en Linux u otro sistema con el sistema de archivos / proc, en este ejemplo, solo puede ver que el proceso 1 se ha estado ejecutando desde el 22 de junio, pero no hay indicación de la hora en que se inició.
stat /proc/<pid>
le dará una respuesta más precisa. Por ejemplo, aquí hay una marca de tiempo exacta para el proceso 1, que ps muestra solo 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
Perl''s Proc :: ProcessTable hará el truco: http://search.cpan.org/dist/Proc-ProcessTable/
Puede instalarlo en debian o ubuntu con sudo apt-get install libproc-processtable-perl
Aquí hay un trazador de líneas:
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 formateado, póngalo 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";
}
}
luego ejecuta perl process.pl
Esto le da más versatilidad y una resolución de 1 segundo en la hora de inicio.
Puede usar bc
para unir los dos comandos en la respuesta de mob y obtener cuántos segundos transcurrieron desde que comenzó el proceso:
echo `date +%s` - `stat -t /proc/<pid> | awk ''{print $14}''` | bc
editar:
Fuera del aburrimiento mientras esperaban que se ejecutaran procesos largos, esto es lo que salió después de algunos 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 pones esto en tu camino y lo llamas así: desde entonces
imprimirá el proceso cmdline y segundos desde que comenzó. También puedes 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 corres:
greptime <pattern>
donde los patrones son una cadena o expresión regular extendida, imprimirá todos los procesos que coincidan con este patrón y los segundos desde que comenzaron. :)
Si solo necesitan ser asesinados:
if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi
Si quieres ver lo que coincide
if [[ "$(uname)" = "Linux" ]];then killall -i --older-than 1h someprocessname;fi
La bandera -i
indicará sí / no para cada coincidencia de proceso.
hacer una ps -aef
. esto le mostrará la hora en que comenzó el proceso. Luego, usando el comando de date
encuentre la hora actual. Calcule la diferencia entre los dos para encontrar la edad del proceso.
stat -t /proc/<pid> | awk ''{print $14}''
para obtener la hora de inicio del proceso en segundos desde la época. Compare con la hora actual ( date +%s
) para obtener la edad actual del proceso.