2008-08-08 17 views
65

Ich habe ein Problem mit einigen Zombie-ähnlichen Prozessen auf einem bestimmten Server, die hin und wieder getötet werden müssen. Wie kann ich diejenigen am besten identifizieren, die länger als eine Stunde gelaufen sind?Wie tötet man alle Linux-Prozesse, die älter als ein bestimmtes Alter sind?

+5

In Linux verwenden 'killall -i --older-als 1h someprocessname' – sanmai

+0

Oder meine Antwort sehen, die' pgrep' verwendet und ist somit flexibler als 'killall'. – g33kz0r

Antwort

28

Wenn sie müssen nur getötet werden:

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

Wenn Sie sehen wollen, wie es ist

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

Die -i Flagge wird Sie auffordern, mit ja/nein für jeden Prozess Spiel.

+0

Guter Tipp. Ich stolperte über den --older - Schalter als später, aber das -i macht es nützlich für die Überprüfung vor dem Töten wer weiß was. – yukondude

+3

Was ist der Sinn von 'if [[" $ (uname) "=" Linux "]];'? Ist der relevante Teil nicht nur der 'killall' Befehl? (Es scheint, dass die umgebende "if" -Klausel entfernt werden könnte, um diese Antwort etwas direkter zu machen.) – rinogo

+0

@ringo Da killall auf einigen Systemen (z. B. Solaris) ein ganz anderer Befehl ist.Unter Solaris werden alle Befehle beendet. – ctc

0

Mit ps ist der richtige Weg. Ich habe schon einmal etwas Ähnliches gemacht, habe aber die Quelle nicht zur Hand. Im Allgemeinen - PS hat eine Option zu sagen, welche Felder angezeigt werden und nach dem sortiert werden. Sie können die Ausgabe nach Laufzeit sortieren, den gewünschten Prozess grep und dann beenden.

HTH

22

Für alles, was älter als einen Tag,

ps aux 

geben Ihnen die Antwort, aber es fällt auf Tages Präzision nach unten, die nicht so nützlich sein könnten.

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] 

Wenn Sie auf Linux oder ein anderes System mit dem/proc-Dateisystem, in diesem Beispiel kann man das Verfahren sieht nur 1 ist seit dem 22. Juni läuft, aber kein Hinweis auf die Zeit es gestartet wurde.

stat /proc/<pid> 

wird Ihnen eine genauere Antwort geben. Zum Beispiel, hier ist ein genauer Zeitstempel für Prozess 1, die ps nur als Jun22 zeigt:

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 
+0

Es scheint, dass 'ps' und' stat' unterschiedliche Ergebnisse für mich zeigen. 'ps' zeigt, dass der Prozess vor 1 Tag gestartet wurde und Statistiken zeigen, dass das heute begann. Warum? – pl1nk

+0

Beachten Sie, dass die Spalte 'TIME' in' ps' die tatsächliche Laufzeit eines Prozesses nicht anzeigt. Es zeigt die kumulierte CPU-Zeit des Prozesses an - die Zeit, die die CPUs mit dem Prozess gearbeitet haben. –

+0

danke, stat/proc/ gab mir genaues Ergebnis für die Prozesslebensdauer (Startzeit) – baptx

36

eine Antwort gefunden, die für mich funktioniert:

Warnung: Dies wird finden und lange laufende Prozesse töten

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

(Wo Benutzer-ID ist ein spezifischer ID des Benutzers mit langen Laufe Prozessen.)

Der zweite reguläre Ausdruck entspricht einer a-Zeit, die eine optionale Zahl für Tage hat, gefolgt von einer Stunde, einer Minute und einer zweiten Komponente, und ist daher mindestens eine Stunde lang.

+5

Umm, bringen Sie den Prozess um? Ich hoffe, die Leute erkennen, dass dieser Code nicht nur findet, sondern auch tötet, oder sie könnten sich aufregen. –

+0

@ButtleButkus Guter Punkt. Ja, der ganze Grund für die Frage war, die alten Prozesse zu finden und sie zu töten, aber das wird nicht explizit explizit erwähnt. Hinweis für andere: Ignorieren Sie das letzte kleine Stück der Leitung, es sei denn, Sie freuen sich über wütende Anrufe von Benutzern. – yukondude

+2

wtf! Bitte ändere den Titel der Frage. Zum Glück habe ich den Prozess nicht! –

9

Auf diese Weise können Sie die Liste der zehn ältesten Prozesse erhalten:

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

gute Sachen, danke dafür. –

+0

Tatsächlich gibt Ihnen das die 10 letzten Prozesse, weil es standardmäßig STIME anzeigt, welches die Zeit ist, zu der das Programm gestartet wurde. Wenn es ETIME anzeigt, was die verstrichene Zeit seit dem Programmstart ist, dann wäre dies korrekt. –

2

ein ps -aef tun. Dies zeigt Ihnen den Zeitpunkt, zu dem der Prozess gestartet wurde. Dann mit dem date Befehl die aktuelle Zeit finden. Berechnen Sie den Unterschied zwischen den beiden, um das Alter des Prozesses zu ermitteln.

+0

Leider ist die hier ausgegebene Zeit schwer zu analysieren. Es kann "HH: MM" für kurz laufende Prozesse sein, oder "MonDD" (möglicherweise lokalisiert!) Oder sogar nur das Jahr für sehr lang laufende Prozesse. –

7

Perl Proc :: ProcessTable den Trick: http://search.cpan.org/dist/Proc-ProcessTable/

Sie können es in debian installieren oder ubuntu mit sudo apt-get install libproc-processtable-perl

Hier ist ein Einzeiler:

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

Oder mehr formatiert, legen Sie dies in eine Datei namens Prozess.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"; 
    } 
} 

dann laufen perl process.pl

Dies gibt Ihnen mehr Vielseitigkeit und 1-Sekunden-Auflösung auf Startzeit.

1

habe ich etwas Ähnliches wie die akzeptierte Antwort, aber etwas anders, da ich auf Prozessnamen basiert übereinstimmen soll und auf der Grundlage der schlechten Prozess für mehr als 100 Sekunden laufen

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

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

zu erhalten die Startzeit des Prozesses in Sekunden seit der Epoche. Vergleichen Sie mit der aktuellen Zeit (date +%s), um das aktuelle Alter des Prozesses zu erhalten. jemand dies in C benötigt

+0

Wir können die beiden Befehle verbinden, um Sekunden seit dem Start des Prozesses zu bekommen: "echo' stat -t/proc/ | awk '{print $ 14}' '-' Datum +% s' | bc " –

+1

Dies wird nicht immer habe recht - zumindest nicht für Linux 2.6 Systeme. Ich habe einen Prozess, der um 9:49 begann, aber stat-t (und stat) zeigen, dass es um 13:14 begann. –

+0

@ dpk: manchmal haben Sie einen Hauptprozess und einige Gabeln laufen. Der Hauptprozess sollte 9:49 Uhr sein, aber der Child-Prozess kann eine neuere Zeit haben. Gleiches gilt für die Threads eines Prozesses. – higuita

0

Im Fall können Sie readproc.h und libproc verwenden:

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

Sie können bc verwenden, um die beiden Befehle in mob Antwort zu verbinden und wie viele Sekunden ellapsed erhalten, da der Prozess gestartet:

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

edit:

Out Langeweile während für lange Prozesse warten, um zu laufen ist es das, was nach ein paar Minuten kam das Hantieren:

#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 

Wenn Sie diese auf Ihrem Weg setzen und es so nennen: sincetime

es wird die Prozess cmdline und Sekunden seit dem Start gedruckt. Sie können dies auch in den Weg stellen:

#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 

Und als wenn Sie laufen:

greptime <pattern> 

wo Muster ein String oder erweiterte reguläre Ausdrücke, werden alle Prozesse dieses Muster passende ausdrucken und die Sekunden seit sie angefangen haben. :)

7

Jodie C und andere haben darauf hingewiesen, dass verwendet werden kann, was in Ordnung ist, wenn Sie den Prozessnamen verwenden möchten, um zu töten. Aber wenn Sie mit den gleichen Parametern wie pgrep -f töten wollen, müssen Sie etwas wie folgt verwenden, mit reinem Bash und dem /proc Dateisystem.

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

Auf diese Weise können Sie als max_age Sekunden finden und ältere Prozesse töten mit dem vollständigen Prozessnamen; d.h., kann der Prozess mit dem Namen /usr/bin/python2 offlineimap mit Bezug auf "offlineimap" beendet werden, während die killall Lösungen, die hier vorgestellt werden, nur auf der Zeichenfolge "python2" funktionieren.

0

Stieß auf somewhere..thought es einfach und nützlich ist

Sie den Befehl in crontab direkt verwenden können,

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

oder wir es als Shell-Skript schreiben,

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

Und es wie so, crontab nennen

* * * * * longprockill.sh