Come posso uccidere i processi più vecchi di "t"?


14

Innanzitutto, sì, ho visto questa domanda:

Trova (e uccidi) vecchi processi

Le risposte sono errate e non funzionano. Ho votato e commentato di conseguenza.

I processi che voglio uccidere sembrano così se elencati 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 Set07 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 24448 0,0 0,0 7000 1432? S Set07 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

Sto cercando di impostare un semplice cron giornaliero che troverà e ucciderà tutti i page.pyprocessi più vecchi di un'ora.

La risposta accettata sulla domanda di cui sopra non funziona, poiché non corrisponde a un intervallo di volte, corrisponde semplicemente a processi in esecuzione da 7 giorni a 7 giorni 23 ore 59 minuti e 59 secondi. Non voglio uccidere i processi in esecuzione da 1-2 ore, ma piuttosto qualcosa di più grande di 1 ora.

L'altra risposta alla domanda sopra menzionata findnon funziona, almeno non su Gentoo o CentOS 5.4, o emette un avviso o non restituisce nulla se viene seguito il consiglio di detto avviso.

Risposte:


22

GNU Killall può uccidere i processi più vecchi di una data età, usando il loro nome processo.

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

1
Tale opzione non è disponibile su CentOS 6.6. Versione: killall (PSmisc) 22.6.
Onnonimo,

9

Grazie alla risposta di Christopher sono stato in grado di adattarlo a quanto segue:

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

-mmin era il comando find che mi mancava.


3
Non sono sicuro se -mmin sia adatto per rilevare l'età di un processo.
LatinSuD,

Non sembra che le directory / proc / vengano modificate molto, quindi questo sembra funzionare. Detto questo, non vorrei affermare che è impossibile.
Christopher Karel,

Non credo che questo risponda alla tua domanda poiché questa risposta è troppo stretta e la domanda è più ampia.
poige

E direi ancora di più - non funziona affatto: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init non viene elencato nonostante i tempi di attività contino per giorni, non per ore. Sembra che non si possa fare affidamento sul tempo di modifica delle directory di / proc /.
poige

3
I timestamp in / proc non possono dipendere da questo, sfortunatamente. Almeno non più.
dpk,

8

find non funziona sempre, non tutti i sistemi hanno etimes disponibili e potrebbe essere il mio status regex newb, ma non penso che tu abbia bisogno di qualcosa di più di questo:

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • elenca tutti i processi e fornisce colonne PID, ELAPSED (etimes = secondi), COMMAND, USER, TT (grazie a @ahoffman)
  • con awk stampa il PID in cui la quarta colonna ($ 4, USER) contiene il testo 'builder', e la quinta colonna ($ 5, TT) contiene il testo 'pts' e la colonna ELAPSED ha un valore maggiore di 600 sec (grazie @amtd)

puoi quindi convogliarlo per uccidere o qualunque sia il tuo bisogno.


Penso che questa sia una delle soluzioni più solide, soprattutto in termini di utilizzo ps, ma piegherei i multipli greps nel singolo awke per sicurezza limiterei le corrispondenze di pattern a colonne particolari (per escludere, ad esempio, la corrispondenza di un nome di comando costruttore, ecc.)
jmtd

Questo va bene quando il tuo intervallo di tempo è in giorni, ma non funzionerà se vuoi testare il tempo trascorso in ore, minuti o secondi.
Vlastimil Ovčáčík,

usa "etimes" invece di "etime", questo restituirà il tempo trascorso in secondi che è molto più facile da analizzare.
ahofmann,

@jmtd & ahofmann: ho aggiornato come da tuo commento. Spero che sia come intendevi
eugenevd,

5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Se lo desideri, puoi alimentare un pselenco di PID da cercare all'interno, ad esempio:

ps h -O etimes 1 2 3

2
etimesfunziona solo per i più recentips
Tino,

4

Penso che tu possa modificare alcune di quelle risposte precedenti per soddisfare le tue esigenze. Vale a dire:

per FILE in (trova. -maxdepth 1 -user processuser -type d -mmin +60)
  do kill -9 $ (basename $ FILE) # Non riesco mai a far funzionare basename con exec di find. Fammi sapere se sai come!
fatto

O

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

Penso che il secondo possa adattarsi meglio alle tue esigenze. La versione di ricerca finirebbe col nuotare altri processi da quell'utente:


Christopher Karel


7
Non usare kill -9se non come ultima risorsa. Usa -SIGINTo -SIGTERM.
In pausa fino a ulteriore avviso.

Questo utilizza il formato del tempo trascorso come criterio di prova, non il suo valore. psfornirà l'ora nel ^..:..$formato quando è inferiore a un'ora.
Vlastimil Ovčáčík,

4
apt-get install psmisc

killall -o 1h $proc_name

Potresti aiutare a spiegare di più psmiscsull'utilità? L'OP ha menzionato CentOS; è disponibile come RPM?
Castaglia,

4

Il problema

Conversione etimedella colonna del pscomando (tempo trascorso) in secondi. Le specifiche del tempo sono in questo formato [[dd-]hh:]mm:ss. Le versioni più recenti di pshanno una etimescolonna che genera etimevalore in secondi.

La soluzione: semplice funzione awk personalizzata

Questa funzione di awk personalizzata supporta tutti i formati di etimecolonna (ad es . 03-12:30:59, 00:07Ecc.). Basta incollarlo nel tuo script awk, è una soluzione amichevole di una riga.

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) converte T in secondi
  • Tspecifica temporale nel [[dd-]hh:]mm:ssformato (ad es. etime)
  • Cconteggio dei campi in T(equivalente alla variabile NF di awk)
  • A matrice di campi in T (equivalente alla variabile $ di awk)
  • A[C>3?C-3:99]questo è un modo sicuro per fare riferimento al quarto valore (cioè il numero di giorni) in ordine inverso. Questo approccio è utile perché giorni e ore sono opzionali. Se l'array non è abbastanza lungo, dereference A[99]che produrrà0 valore. Presumo 99sia abbastanza alto per la maggior parte dei casi d'uso.
  • restituisce i secondi come numero intero

Esempio del mondo reale

Questo basel oneliner interromperà il soffice.binprocesso in esecuzione con l'utente corrente se il processo è più vecchio di 180 secondi.

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

1
MOLTO meglio che l'altro risponda. gestisce anche più processi.
Denny Weinberg,

Sarebbe meglio posizionare 'command' o 'args' alla fine dell'elenco dei formati 'ps' per poter eseguire il grep sulla stringa comando / args completa. Posizionandolo all'inizio, ps troncerà i comandi più lunghi.
Maksym,

1

Il lstartcampo in psfornisce un formato orario coerente che possiamo alimentare dateper convertire in secondi dall'epoca. Quindi lo confrontiamo con l'ora corrente.

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

0

Ho modificato la risposta che ti hanno dato nel post precedente

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

L'espressione regolare cerca 2 tipi di secondo argomento:

  • Giorni sotto forma di cifre e segno meno.
  • Hours:minutes:seconds espressione.

Ciò dovrebbe corrispondere a tutto tranne che ai processi giovani che avrebbero la forma minutes:seconds.


In alternativa, potremmo provare a farlo nel modo in cui lo fa PS. Sottrai il primo argomento di / proc / uptime dal 22 ° argomento di / proc / * / stat.
LatinSuD,

0

Questo è probabilmente eccessivo, ma mi sono incuriosito abbastanza per finirlo e testare che funzioni (con un nome di processo diverso sul mio sistema, ovviamente). Puoi uccidere la cattura di $usere$pid semplificare la regexp, che ho aggiunto solo per il debug e che non mi andava di strappare indietro. Le acquisizioni con nome da perl 5.10 si raderebbero un paio di righe in più, ma questo dovrebbe funzionare su perls più vecchi.

Dovrai sostituire la stampa con un'uccisione, ovviamente, ma non avevo intenzione di uccidere nulla sul mio 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";                                                               
    }                                                                                 
}


0

Ho un server con date errate in / proc e find non funziona, quindi ho scritto questo 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 "

0

Versione Python usando il ctime delle voci di processo in /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

0

Uso questo semplice script che richiede due argomenti: nome del processo ed età in secondi.

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

0

questo dovrebbe funzionare

killall --older-than 1h $proc_name


1
In che modo questo aggiunge o migliora [le risposte già esistenti]?
Reagisce il

2
@Reaces: In tutta onestà, ho dovuto cercare l'unica risposta menzionata --older-than ed è facile trascurarla. Rispetto alle altre risposte, questo è molto più semplice ed è ora disponibile anche su EL7.
Sven

@Reces questo rende più semplice la scrittura di script usando awk / sed ecc per uccidere un processo, questo suppongo sia molto più semplice e più pulito
Jabir Ahmed,

0

Non ero soddisfatto dell'altra soluzione, molti di loro sono troppo criptici (la mia conoscenza bash è un po 'limitata) e quindi non posso personalizzarli ...
Ho creato la mia soluzione, probabilmente non è la migliore ma funziona e è leggibile

Puoi salvare questo script in un file e renderlo eseguibile (eventualmente chiamalo con 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

-2

72 = 3 giorni 48 = 2 giorni 24 = 1 giorno

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

Funziona :)


1
Potrebbe anche essere, ma è piuttosto difficile da leggere e da cui imparare. Prendi in considerazione la riformattazione con alcune nuove righe e cose ... gli script sono meglio di una riga per le istruzioni.
Falcon Momot,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.