Come uccidi tutti i processi Linux che sono più vecchi di una certa età?

Ho un problema con alcuni processi simili a zombie su un server che devono essere uccisi di tanto in tanto. Come posso identificare meglio quelli che durano da più di un’ora?

Se hanno solo bisogno di essere uccisi:

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

Se vuoi vedere qual è la corrispondenza

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

Il flag -i ti chiederà di confermare con yes / no per ogni match del processo.

Ho trovato una risposta che funziona per me:

avvertimento: questo troverà e ucciderà i processi di lunga durata

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

(Dove user-id è un ID utente specifico con processi di lunga durata.)

La seconda espressione regolare corrisponde al tempo che ha una figura di giorni facoltativi, seguita da un’ora, minuti e secondi componenti, e quindi è lunga almeno un’ora.

Per qualcosa di più vecchio di un giorno,

 ps aux 

ti darà la risposta, ma scende alla precisione del giorno che potrebbe non essere così utile.

 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] 

Se sei su linux o su un altro sistema con il filesystem / proc, in questo esempio puoi vedere solo che il processo 1 è in esecuzione dal 22 giugno, ma non indica il momento in cui è stato avviato.

 stat /proc/ 

ti darà una risposta più precisa. Ad esempio, ecco un timestamp esatto per il processo 1, che ps mostra solo come 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 

In questo modo è ansible ottenere l’elenco dei dieci processi più vecchi:

  ps -elf |  ordina -r -k12 |  testa -n 10 

Perl’s Proc :: ProcessTable farà il trucco: http://search.cpan.org/dist/Proc-ProcessTable/

Puoi installarlo in debian o ubuntu con sudo apt-get install libproc-processtable-perl

Ecco un one-liner:

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

Oppure, più formattato, mettilo in un file chiamato 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"; } } 

quindi eseguire perl process.pl

Questo ti dà più versatilità e risoluzione di 1 secondo al momento dell’avvio.

Jodie C e altri hanno sottolineato che killall -i può essere usato, il che va bene se si vuole usare il nome del processo per uccidere. Ma se vuoi uccidere con gli stessi parametri di pgrep -f , devi usare qualcosa come il seguente, usando bash puro e il filesystem /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 

Questo ti permette di trovare e uccidere processi più vecchi di max_age secondi usando il nome completo del processo ; cioè, il processo denominato /usr/bin/python2 offlineimap può essere ucciso con riferimento a “offlineimap”, mentre le soluzioni killall qui presentate funzioneranno solo sulla stringa “python2”.

Puoi usare bc per unire i due comandi nella risposta di mob e ottenere quanti secondi sono trascorsi dall’inizio del processo:

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

modificare:

Per la noia in attesa di lunghi processi da eseguire, questo è ciò che è venuto fuori dopo pochi minuti giocherellando:

 #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 

Se lo metti sul tuo percorso e lo chiami così: sincetime

stamperà la cmdline del processo e i secondi da quando è stato avviato. Puoi anche metterlo nel tuo percorso:

 #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 

E se corri:

 greptime  

dove pattern è una stringa o un’espressione regolare estesa, stamperà tutti i processi che corrispondono a questo modello e ai secondi da quando sono stati avviati. 🙂

fai un ps -aef . questo ti mostrerà il momento in cui è iniziato il processo. Quindi, utilizzando il comando date trova l’ora corrente. Calcola la differenza tra i due per trovare l’età del processo.

Ho fatto qualcosa di simile alla risposta accettata, ma in modo leggermente diverso dal momento che voglio corrispondere in base al nome del processo e in base al processo non valido in esecuzione per più di 100 secondi

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

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

per ottenere l’ora di inizio del processo in pochi secondi dall’epoca. Confronta con l’ora corrente ( date +%s ) per ottenere l’età attuale del processo.

Usare ps è la strada giusta. Ho già fatto qualcosa di simile prima, ma non ho la fonte a portata di mano. Generalmente, ps ha la possibilità di dirgli quali campi mostrare e da quale ordinare. È ansible ordinare l’output eseguendo il tempo, grep il processo che si desidera e quindi ucciderlo.

HTH

Nel caso in cui qualcuno abbia bisogno di questo in C, puoi usare readproc.h e libproc:

 #include  #include  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; } 

È venuto da qualche parte..anche pensato è semplice e utile

Puoi usare direttamente il comando in crontab,

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

oppure, possiamo scrivere come script di shell,

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

E chiamalo crontab in questo modo,

 * * * * * longprockill.sh 

La mia versione di sincetime sopra di @Rafael S. Calsaverini:

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

Questo inverte i campi di output: tempo trascorso prima, comando completo inclusi argomenti secondo. Questo è preferito perché il comando completo può contenere spazi.