Wie beendet man alle Linux-Prozesse, die älter als ein bestimmtes Alter sind?
Frage
Ich habe ein Problem mit einigen zombieähnlichen Prozessen auf einem bestimmten Server, die hin und wieder beendet werden müssen.Wie kann ich am besten diejenigen identifizieren, die länger als etwa eine Stunde gelaufen sind?
Lösung
Wenn sie nur getötet werden müssen:
if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi
Wenn Sie sehen möchten, was dazu passt
if [[ "$(uname)" = "Linux" ]];then killall -i --older-than 1h someprocessname;fi
Der -i
Flag fordert Sie für jede Prozessübereinstimmung mit Ja/Nein auf.
Andere Tipps
Ich habe eine Antwort gefunden, die für mich funktioniert:
Warnung:das wird finden und töten lang laufende Prozesse
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 die ID eines bestimmten Benutzers mit lang laufenden Prozessen.)
Der zweite reguläre Ausdruck entspricht einer Zeit, die optional eine Tageszahl enthält, gefolgt von einer Stunde, einer Minute und einer zweiten Komponente und daher mindestens eine Stunde lang ist.
Für alles, was älter als einen Tag ist,
ps aux
wird Ihnen die Antwort geben, aber sie sinkt auf die Tagesgenauigkeit, was möglicherweise nicht so nützlich ist.
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 Linux oder ein anderes System mit dem /proc-Dateisystem verwenden, können Sie in diesem Beispiel nur sehen, dass Prozess 1 seit dem 22. Juni ausgeführt wird, aber keine Angabe zum Zeitpunkt des Starts.
stat /proc/<pid>
werde Dir eine genauere Antwort geben.Hier ist zum Beispiel ein genauer Zeitstempel für Prozess 1, der ps nur als Jun22 anzeigt:
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
Auf diese Weise erhalten Sie die Liste der zehn ältesten Prozesse:
ps -elf | sort -r -k12 | head -n 10
Jodie C und andere haben darauf hingewiesen killall -i
kann verwendet werden, was in Ordnung ist, wenn Sie den Prozessnamen zum Beenden verwenden möchten.Aber wenn Sie mit den gleichen Parametern töten möchten wie pgrep -f
, müssen Sie etwas wie das Folgende verwenden, indem Sie pure bash und das verwenden /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 Prozesse finden und beenden, die älter sind als max_age
Sekunden mit der Vollständiger Prozessname;d. h. der genannte Prozess /usr/bin/python2 offlineimap
kann durch Verweis auf „offlineimap“ getötet werden, wohingegen die killall
Die hier vorgestellten Lösungen funktionieren nur mit der Zeichenfolge „python2“.
Perls Proc::ProcessTable erledigt den Zweck:http://search.cpan.org/dist/Proc-ProcessTable/
Sie können es in Debian oder Ubuntu mit installieren 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 formatierter: Fügen Sie dies in eine Datei namens „process.pl“ ein:
#!/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 renne perl process.pl
Dies bietet Ihnen mehr Vielseitigkeit und eine Auflösung von 1 Sekunde bei der Startzeit.
Sie können verwenden bc
um die beiden Befehle in Mobs Antwort zu verbinden und zu ermitteln, wie viele Sekunden seit Beginn des Prozesses vergangen sind:
echo `date +%s` - `stat -t /proc/<pid> | awk '{print $14}'` | bc
bearbeiten:
Aus Langeweile beim Warten auf lange Prozesse ist nach ein paar Minuten Fummelei Folgendes herausgekommen:
#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 dies auf Ihren Weg bringen und es so nennen:seit jeher
Es werden die Befehlszeile und die Sekunden seit dem Start des Prozesses ausgegeben.Sie können dies auch in Ihren Pfad einfügen:
#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 wenn Sie laufen:
greptime <pattern>
Wenn „Muster“ eine Zeichenfolge oder ein erweiterter regulärer Ausdruck ist, werden alle Prozesse, die diesem Muster entsprechen, und die Sekunden seit ihrem Start ausgedruckt.:) :)
mach ein ps -aef
.Dadurch wird Ihnen der Zeitpunkt angezeigt, zu dem der Vorgang gestartet wurde.Dann verwenden Sie die date
Befehl findet die aktuelle Uhrzeit.Berechnen Sie die Differenz zwischen beiden, um das Alter des Prozesses zu ermitteln.
Ich habe etwas Ähnliches wie die akzeptierte Antwort gemacht, aber etwas anders, da ich eine Übereinstimmung basierend auf dem Prozessnamen und basierend auf dem fehlerhaften Prozess, der länger als 100 Sekunden läuft, abgleichen möchte
kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')
stat -t /proc/<pid> | awk '{print $14}'
um die Startzeit des Prozesses in Sekunden seit der Epoche zu erhalten.Vergleichen Sie mit der aktuellen Zeit (date +%s
), um das aktuelle Alter des Prozesses zu ermitteln.
Die Verwendung von ps ist der richtige Weg.Ich habe schon einmal etwas Ähnliches gemacht, habe aber die Quelle nicht zur Hand.Im Allgemeinen verfügt ps über die Option, anzugeben, welche Felder angezeigt und nach welchen sortiert werden sollen.Sie können die Ausgabe nach Laufzeit sortieren, den gewünschten Prozess durchsuchen und ihn dann beenden.
HTH
Falls jemand dies in C benötigt, 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;
}
Irgendwo entdeckt. Ich dachte, es ist einfach und nützlich
Sie können den Befehl direkt in crontab verwenden.
* * * * * ps -lf | grep "user" | perl -ane '($h,$m,$s) = split /:/,$F
+[13]; kill 9, $F[3] if ($h > 1);'
oder wir können 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 nenne es Crontab so,
* * * * * longprockill.sh
Meine Version von sincetime
oben von @Rafael S.Calsaverini:
#!/bin/bash
ps --no-headers -o etimes,args "$1"
Dadurch werden die Ausgabefelder umgekehrt:Zuerst die verstrichene Zeit, dann der vollständige Befehl einschließlich der Argumente.Dies wird bevorzugt, da der vollständige Befehl Leerzeichen enthalten kann.