¿Cómo elimino procesos anteriores a "t"?

14

Primero, sí, he visto esta pregunta:

Encuentra (y elimina) procesos antiguos

Las respuestas allí son incorrectas y no funcionan. He votado y comentado en consecuencia.

Los procesos que quiero matar se ven así cuando se enumeran con ps aux | grep page.py:

apache 424 0.0 0.1 6996 4564? S 07:02 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 2686 0.0 0.1 7000 3460? S Sep10 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 2926 0.0 0.0 6996 1404? S Sep02 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 7398 0.0 0.0 6996 1400? S Sep01 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 9423 0.0 0.1 6996 3824? S Sep10 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 11022 0.0 0.0 7004 1400? S Sep01 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15343 0.0 0.1 7004 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15364 0.0 0.1 7004 3792? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15397 0.0 0.1 6996 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 16817 0.0 0.1 7000 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 17590 0.0 0.0 7000 1432? S Sep07 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 24448 0.0 0.0 7000 1432? S Sep07 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 30361 0.0 0.1 6996 3776? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py

Estoy buscando configurar un cron diario simple que encuentre y elimine los page.pyprocesos anteriores a una hora.

La respuesta aceptada en la pregunta antes mencionada no funciona, ya que no coincide con un rango de veces, simplemente coincide con los procesos que se han estado ejecutando de 7 días a 7 días 23 horas 59 minutos y 59 segundos. No quiero matar los procesos que se han estado ejecutando de 1 a 2 horas, sino más de 1 hora.

La otra respuesta a la pregunta anterior usando findno funciona, al menos no en Gentoo o CentOS 5.4, o escupe una advertencia o no devuelve nada si se sigue el consejo de dicha advertencia.

hobodave
fuente

Respuestas:

22

GNU Killall puede matar procesos anteriores a una edad determinada, utilizando su nombre de proceso.

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h page.py;fi
Jodie C
fuente
1
Esa opción no está disponible en CentOS 6.6. Versión: killall (PSmisc) 22.6.
Onnónimo el
9

Gracias a la respuesta de Christopher pude adaptarlo a lo siguiente:

find /proc -maxdepth 1 -user apache -type d -mmin +60 -exec basename {} \; \
| xargs ps | grep page.py | awk '{ print $1 }' | sudo xargs kill

-mmin fue el comando de encontrar que me faltaba.

hobodave
fuente
3
No estoy seguro si -mmin es adecuado para detectar la edad de un proceso.
LatinSuD
No parece que los directorios / proc / se modifiquen mucho, por lo que parece funcionar. Dicho esto, no quisiera afirmar que es imposible.
Christopher Karel
No creo que esto responda a su pregunta ya que esta respuesta es demasiado limitada y la pregunta es más amplia.
Poige
Y diría aún más: no funciona en absoluto: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init no aparece en la lista a pesar del tiempo de actividad de días, no de horas. Parece que no puede confiar en el tiempo de modificación de directorios de / proc /.
Poige
3
Lamentablemente, no se puede depender de las marcas de tiempo en / proc para esto. Al menos no más.
dpk
8

find no siempre funciona, no todos los sistemas tienen ediciones disponibles, y podría ser mi estado regex newb, pero no creo que necesite nada más que esto:

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • enumere todos los procesos y proporcione columnas PID, ELAPSED (etimes = segundos), COMMAND, USER, TT (gracias @ahoffman)
  • con awk imprime el PID donde la 4ta columna ($ 4, USUARIO) contiene texto 'constructor', y la 5ta columna ($ 5, TT) contiene texto 'pts' y la columna ELAPSED tiene un valor mayor de 600 segundos (gracias @amtd)

entonces puedes canalizar eso para matar o lo que sea que necesites.

eugenevd
fuente
Creo que esta es una de las soluciones más robustas, especialmente en términos de su uso de ps, pero doblaría los múltiples greps en el único awk, y por seguridad restringiría las coincidencias de patrones a columnas particulares (para descartar, por ejemplo, una coincidencia de nombre de comando constructor, etc.)
jmtd
Esto está bien cuando su alcance de tiempo es en días, pero no funcionará si desea probar el tiempo transcurrido en horas, minutos o segundos.
Vlastimil Ovčáčík
use "etimes" en lugar de "etime", esto devolverá el tiempo transcurrido en segundos, que es mucho más fácil de analizar.
ahofmann
@jmtd & ahofmann: He actualizado según su comentario. Espero que esto sea lo que pretendías
eugenevd
5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Si lo desea, puede alimentar pscon una lista de PID para buscar, por ejemplo:

ps h -O etimes 1 2 3
poige
fuente
2
etimesfunciona solo para nuevosps
Tino
4

Creo que puede modificar algunas de esas respuestas anteriores para satisfacer sus necesidades. A saber:

para FILE in (find. -maxdepth 1 -user processuser -type d -mmin +60)
  do kill -9 $ (basename $ FILE) # Nunca puedo hacer que basename trabaje con el exec de find. ¡Avísame si sabes cómo!
hecho

O

ps -eo pid, etime, comm | awk '$ 2! ~ /^..:..$/ && $ 3 ~ / page \ .py / {print $ 1}' | matar -9

Creo que el segundo puede ajustarse mejor a tus necesidades. La versión de búsqueda terminaría destruyendo otros procesos de ese usuario:


Christopher Karel

Christopher Karel
fuente
77
No lo use kill -9excepto como último recurso. Use -SIGINTo -SIGTERM.
Pausado hasta nuevo aviso.
Esto está utilizando el formato del tiempo transcurrido como criterio de prueba, no su valor. psgenerará tiempo en ^..:..$formato cuando sea menos de una hora.
Vlastimil Ovčáčík
4
apt-get install psmisc

killall -o 1h $proc_name
Alex
fuente
¿Podría ayudarme a explicar más sobre la psmiscutilidad? El OP mencionó CentOS; ¿Está disponible como RPM?
Castaglia
4

El problema

Convertir la etimecolumna de pscomando (tiempo transcurrido) a segundos. La especificación de tiempo está en este formato [[dd-]hh:]mm:ss. Las versiones más nuevas de pstienen una etimescolumna que genera etimevalor en segundos.

La solución: función awk personalizada simple

Esta función awk personalizada admite todos los formatos de etimecolumna (p 03-12:30:59. Ej. , 00:07Etc.). Simplemente péguelo en su script awk, es una solución amigable.

function sec(T){C=split(T,A,"[:-]"); return A[C>3?C-3:99]*86400 + A[C>2?C-2:99]*3600 + A[C>1?C-1:99]*60 + A[C>0?C-0:99]*1}
  • sec(T) convierte T a segundos
  • Tespecificación de tiempo en [[dd-]hh:]mm:ssformato (p etime. ej. )
  • Crecuento de campos en T(equivalente a la variable NF de awk)
  • Amatriz de campos en T(equivalente a la variable $ de awk)
  • A[C>3?C-3:99]Esta es una forma segura de hacer referencia al cuarto valor (es decir, número de días) en orden inverso. Este enfoque es útil porque los días y las horas son opcionales. Si la matriz no es lo suficientemente larga, desreferenciará A[99]lo que arrojará 0valor. Supongo que 99es lo suficientemente alto para la mayoría de los casos de uso.
  • devuelve segundos como entero

Ejemplo del mundo real

Este bash oneliner matará el soffice.binproceso que se ejecuta bajo el usuario actual si el proceso es anterior a 180 segundos.

kill -9 $(ps cx -o command,etime,pid | awk '/^soffice.bin/ {if (sec($2)>180) {print $3}} function sec(T){C=split(T,A,"[:-]"); return A[C>3?C-3:99]*86400 + A[C>2?C-2:99]*3600 + A[C>1?C-1:99]*60 + A[C>0?C-0:99]*1}')
Vlastimil Ovčáčík
fuente
1
MUCHO mejor que las otras respuestas. También maneja múltiples procs.
Denny Weinberg
Sería mejor colocar 'comando' o 'args' al final de la lista de formatos 'ps' para poder grep en la cadena completa de comandos / args. Colocarlo al principio llevará a ps truncar los comandos más largos.
Maksym
1

El lstartcampo en psda un formato de tiempo consistente que podemos alimentar datepara convertir a segundos desde la época. Luego solo comparamos eso con la hora actual.

#!/bin/bash
current_time=$(date +%s)
ps axo lstart=,pid=,cmd= |
    grep page.py |
    while read line
    do
        # 60 * 60 is one hour, multiply additional or different factors for other thresholds 
        if (( $(date -d "${line:0:25}" +%s) < current_time - 60 * 60 ))
        then
            echo $line | cut -d ' ' -f 6    # change echo to kill
        fi
    done
Pausado hasta nuevo aviso.
fuente
0

Modifiqué la respuesta que te dieron en la publicación anterior

ps -eo pid,etime,comm | 
egrep '^ *[0-9]+ +([0-9]+-[^ ]*|[0-9]{2}:[0-9]{2}:[0-9]{2}) +/usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py' | 
awk '{print $1}' | 
xargs kill

La expresión regular busca 2 tipos de segundo argumento:

  • Días en forma de dígitos y un signo menos.
  • Hours:minutes:seconds expresión.

Eso debería coincidir con todo, excepto los procesos jóvenes que tendrían la forma minutes:seconds.

LatinSuD
fuente
Alternativamente, podríamos intentar hacerlo como lo hace PS. Reste el primer argumento de / proc / uptime del argumento 22 de / proc / * / stat.
LatinSuD
0

Esto probablemente sea excesivo, pero tuve la curiosidad de terminarlo y probar que funciona (en un nombre de proceso diferente en mi sistema, por supuesto). Puede eliminar la captura $usery $pidsimplificar la expresión regular, que solo agregué para la depuración, y no tenía ganas de volver a salir. Las capturas con nombre de perl 5.10 eliminarían un par de líneas más, pero esto debería funcionar en perls más antiguos.

Necesitará reemplazar la impresión con un kill, por supuesto, pero no estaba dispuesto a matar nada en mi propio sistema.

#!/usr/bin/perl -T
use strict; use warnings;

$ENV{"PATH"} = "/usr/bin:/bin";                                                       

my (undef,undef,$hour) = localtime(time);                                             
my $target = $hour - 2; # Flag process before this hour                               
my $grep = 'page.py';                                                   

my @proclist = `ps -ef | grep $grep`;                                                 
foreach my $proc (@proclist)                                                          
{                                                                                     
    $proc =~ /(\w+)\s+(\d+)\s+\d+\s+\d+\s+(.*?).*/;                   
    my $user = $1;                                                                    
    my $pid = $2;                                                                     
    my $stime = $3;                                                                   

    $stime =~ s/(\d+):(\d+)/$1/;                                                      

    # We're going to do a numeric compare against strings that                        
    # potentially compare things like 'Aug01' when the STIME is old                   
    # enough.  We don't care, and we want to catch those old pids, so                 
    # we just turn the warnings off inside this foreach.                              
    no warnings 'numeric';                                                            

    unless ($stime > $target)                                                         
    {                                                                                 
        print "$pid\n";                                                               
    }                                                                                 
}

Zed
fuente
0

Tengo un servidor con fechas incorrectas en / proc y find no funciona, así que escribí este script:

#!/bin/bash

MAX_DAYS=7  #set the max days you want here
MAX_TIME=$(( $(date +'%s') - $((60*60*24*$MAX_DAYS)) ))

function search_and_destroy()
{
        PATTERN=$1
        for p in $(ps ux|grep "$PATTERN"|grep -v grep| awk '{ print $2 }')
        do
            test $(( $MAX_TIME - $(date -d "`ps -p $p -o lstart=`" +'%s') )) -ge 0 && kill -9 $p
        done
}

search_and_destroy " command1 "
search_and_destroy " command2 "
Vincent
fuente
0

Versión de Python usando el ctime de las entradas de proceso en /proc:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kills processes older than HOURS_DELTA hours

import os, time

SIGNAL=15
HOURS_DELTA=1

pids = [int(pid) for pid in os.listdir('/proc') if pid.isdigit()]

for pid in pids:
    if os.stat(os.path.join('/proc', str(pid))).st_ctime < time.time() - HOURS_DELTA * 3600:
        try:
            os.kill(pid, SIGNAL)
        except:
            print "Couldn't kill process %d" % pid
Eduardo Ivanec
fuente
0

Utilizo este script simple, toma dos argumentos: nombre del proceso y antigüedad en segundos.

#!/bin/bash
# first argument name of the process to check
# second argument maximum age in seconds
# i.e kill lighttpd after 5 minutes
#   script.sh lighttpd 300 
process=$1
maximum_runtime=$2
pid=`pgrep $process`
if [ $? -ne 0 ]
then
        exit 0
fi
process_start_time=`stat /proc/$pid/cmdline --printf '%X'`
current_time=`date +%s`
let diff=$current_time-$process_start_time

if [ $diff -gt $maximum_runtime ]
then
        kill -3 $pid
fi
Sanxiago
fuente
0

Esto debería funcionar

killall --older-than 1h $proc_name

Jabir Ahmed
fuente
1
¿Cómo agrega o mejora esto [las respuestas ya existentes]?
Reaces
2
@Reaces: Para ser justos, tuve que buscar la respuesta que menciona --older-than y es fácil pasarla por alto. En comparación con las otras respuestas, esto es mucho más fácil, y ahora está disponible también en EL7.
Sven
@Reaces esto solo hace que sea más fácil que escribir scripts usando awk / sed, etc. para matar un proceso, esto supongo que es mucho más simple y limpio
Jabir Ahmed
0

No estaba satisfecho con la otra solución, la mayoría de ellos son demasiado crípticos (mi conocimiento básico es un poco limitado) y, por lo tanto, no puedo personalizarlos ...
He creado mi propia solución. Probablemente no sea la mejor, pero funciona y es legible

Puede guardar este script en un archivo y hacerlo ejecutable (eventualmente llamarlo con el uso de cron)

#!/bin/bash
## time in second that trigger the kill
LIMIT=10
## [] skip the grep from the process list
PROC_NAME="[m]y process name"
## etimes return the time in seconds
TIME_SEC=$(ps axo etimes,pid,command | grep "$PROC_NAME" | awk {'print$1'})
PID=$(ps axo etimes,pid,command | grep "$PROC_NAME" | awk {'print$2'})

if [ -n "$TIME_SEC" ] 
    then
    if (( $TIME_SEC > $LIMIT )); then
        kill $PID
    fi
fi
Francesco
fuente
-2

72 = 3 días 48 = 2 días 24 = 1 día

a1=$(TZ=72 date +%d) ps -ef| cat filex.txt | sed '/[JFMASOND][aepuco][nbrylgptvc] '$a1'/!d' | awk '{ print $2 " " $5 " " $6 }' > file2.txt

funciona :)

onkar
fuente
1
Bien puede ser, pero es bastante difícil de leer y aprender. Considere volver a formatear con algunas líneas nuevas y otras cosas ... las secuencias de comandos son mejores que las frases sencillas para la instrucción.
Falcon Momot