Wie kann ich Prozesse beenden, die älter als "t" sind?

14

Erstens, ja, ich habe diese Frage gesehen:

Finden (und beenden) Sie alte Prozesse

Die Antworten dort sind falsch und funktionieren nicht. Ich habe entsprechend abgestimmt und kommentiert.

Die Prozesse, die ich beenden möchte, sehen wie folgt aus 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 09.09. 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
Apache 15364 0,0 0,1 7004 3792? S 09.09. 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
Apache 15397 0,0 0,1 6996 3788? S 09.09. 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
Apache 16817 0,0 0,1 7000 3788? S 09.09. 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 09.09. 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py

Ich suche nach einem einfachen täglichen Cron, der alle page.pyProzesse findet und beendet, die älter als eine Stunde sind.

Die akzeptierte Antwort auf die oben genannte Frage funktioniert nicht, da sie nicht mit einem bestimmten Zeitraum übereinstimmt. Sie stimmt einfach mit Prozessen überein, die zwischen 7 Tagen und 7 Tagen, 23 Stunden, 59 Minuten und 59 Sekunden ausgeführt wurden. Ich möchte keine Prozesse beenden, die seit 1-2 Stunden ausgeführt werden, sondern nur Prozesse, die länger als 1 Stunde dauern .

Die andere Antwort auf die oben genannte Frage mit findfunktioniert nicht, zumindest nicht unter Gentoo oder CentOS 5.4. Sie gibt entweder eine Warnung aus oder gibt nichts zurück, wenn der Hinweis dieser Warnung befolgt wird.

Hobodave
quelle

Antworten:

21

GNU Killall kann Prozesse, die älter als ein bestimmtes Alter sind, unter Verwendung ihres Prozessnamens beenden.

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h page.py;fi
Jodie C
quelle
1
Diese Option ist unter CentOS 6.6 nicht verfügbar. Version: killall (PSmisc) 22.6.
Onnonymous
9

Dank Christophers Antwort konnte ich es an folgendes anpassen:

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

-mmin war der Befehl zum Suchen, den ich vermisst habe.

Hobodave
quelle
3
Wir sind uns nicht sicher, ob -mmin zum Ermitteln des Alters eines Prozesses geeignet ist.
LatinSuD
Es sieht nicht so aus, als ob die / proc / -Verzeichnisse stark verändert würden, also scheint dies zu funktionieren. Davon abgesehen würde ich nicht behaupten wollen, dass es unmöglich ist.
Christopher Karel
Ich glaube nicht, dass dies Ihre Frage beantwortet, da diese Antwort zu eng und die Frage breiter ist.
Poige
Und ich würde noch mehr sagen - es funktioniert überhaupt nicht: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init wird nicht aufgelistet, obwohl die Betriebszeit Tage und nicht Stunden beträgt. Es scheint, dass Sie sich nicht auf die Änderungszeit von / proc / verlassen können.
Poige
3
Die Timestamps in / proc können dafür leider nicht herangezogen werden. Zumindest nicht mehr.
dpk
8

find funktioniert nicht immer, nicht jedes System verfügt über verfügbare Zeiten, und es könnte mein regulärer Newb-Status sein, aber ich glaube nicht, dass Sie mehr als das brauchen:

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • liste alle Prozesse auf und gib die Spalten PID, ELAPSED (etimes = seconds), COMMAND, USER, TT an (danke @ahoffman)
  • mit awk print die PID, wobei die 4. Spalte ($ 4, USER) den Text 'builder' enthält und die 5. Spalte ($ 5, TT) den Text 'pts' enthält und die ELAPSED-Spalte einen Wert größer als 600 sec hat (danke @amtd)

Sie können das dann weiterleiten, um zu töten oder was auch immer Ihre Notwendigkeit sein mag.

eugenevd
quelle
Ich denke, dies ist eine der robusteren Lösungen, insbesondere in Bezug auf Ihre Verwendung von ps, aber ich würde das Vielfache grepzu einem Einfachen falten awkund aus Sicherheitsgründen die Musterübereinstimmungen auf bestimmte Spalten beschränken (um z. B. eine Befehlsnamenübereinstimmung auszuschließen) Baumeister usw.)
jmtd
Dies ist in Ordnung, wenn Ihr Zeitraum in Tagen angegeben ist, funktioniert jedoch nicht, wenn Sie die abgelaufene Zeit in Stunden, Minuten oder Sekunden testen möchten.
Vlastimil Ovčáčík
Verwenden Sie "etimes" anstelle von "etime". Dadurch wird die verstrichene Zeit in Sekunden zurückgegeben, was das Parsen erheblich erleichtert.
Ahofmann
@jmtd & ahofmann: Ich habe nach deinem Kommentar aktualisiert. Ich hoffe, das ist so, wie Sie es beabsichtigt haben
eugenevd
5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Wenn Sie möchten, können Sie eine psListe von PIDs eingeben, in denen nachgeschlagen werden soll, z. B .:

ps h -O etimes 1 2 3
Poige
quelle
2
etimesfunktioniert nur für neuereps
Tino
4

Ich denke, Sie können einige dieser vorherigen Antworten an Ihre Bedürfnisse anpassen. Nämlich:

für DATEI in (finde. -maxtiefe 1 -benutzer prozessbenutzer -type d -mmin +60)
  do kill -9 $ (basename $ FILE) # Ich kann basename niemals mit find's exec arbeiten lassen. Lass es mich wissen, wenn du weißt wie!
erledigt

Oder

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

Ich denke, der zweite passt am besten zu Ihren Bedürfnissen. Die Find-Version würde andere Prozesse des Benutzers -


Christopher Karel - nerven

Christopher Karel
quelle
7
Verwenden Sie es kill -9nur als letzten Ausweg. Verwenden Sie -SIGINToder -SIGTERM.
Bis auf weiteres angehalten.
Hierbei wird das Format der abgelaufenen Zeit als Testkriterium verwendet, nicht der Wert. psGibt die Zeit im ^..:..$Format aus, wenn sie weniger als eine Stunde beträgt.
Vlastimil Ovčáčík
4
apt-get install psmisc

killall -o 1h $proc_name
Alex
quelle
Könnten Sie helfen, mehr über das psmiscDienstprogramm zu erklären ? Das OP erwähnte CentOS; ist es als RPM verfügbar?
Castaglia
4

Das Problem

Umwandeln der etime(abgelaufenen Zeit) psBefehlsspalte in Sekunden. Die Zeitangabe erfolgt in diesem Format [[dd-]hh:]mm:ss. Neuere Versionen von pshaben eine etimesSpalte, die den etimeWert in Sekunden ausgibt .

Die Lösung: einfache Custom-Awk-Funktion

Diese benutzerdefinierten awk Funktion unterstützt alle Formate der etimeSpalte (zB 03-12:30:59, 00:07etc.). Fügen Sie es einfach in Ihr awk-Skript ein, es ist eine einzeilige, benutzerfreundliche Lösung.

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) konvertiert T in Sekunden
  • TZeitangabe im [[dd-]hh:]mm:ssFormat (zB etime)
  • CAnzahl der Felder in T(entspricht der NF-Variablen von awk)
  • AArray von Feldern in T(entspricht awks $ -Variable)
  • A[C>3?C-3:99]Dies ist eine sichere Methode, um den vierten Wert (dh die Anzahl der Tage) in umgekehrter Reihenfolge zu referenzieren. Dieser Ansatz ist nützlich, da Tage und Stunden optional sind. Wenn das Array nicht lang genug ist, gibt es eine Dereferenzierung, A[99]die einen 0Wert ergibt. Ich gehe davon 99aus, dass es für die meisten Anwendungsfälle hoch genug ist.
  • Gibt Sekunden als Ganzzahl zurück

Beispiel aus der realen Welt

Dieser Bash-Oneliner bricht den soffice.binProzess ab, der unter dem aktuellen Benutzer ausgeführt wird, wenn der Prozess älter als 180 Sekunden ist.

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
quelle
1
VIEL besser als der andere antwortet. Es verarbeitet auch Multi-Procs.
Denny Weinberg
Es wäre besser, 'command' oder 'args' am Ende der 'ps'-Formatliste zu platzieren, um in der Lage zu sein, auf den vollständigen Befehl / args-String zuzugreifen. Wenn Sie es am Anfang platzieren, werden die längeren Befehle von ps abgeschnitten.
Maksym
1

Das lstartFeld in psgibt ein konsistentes Zeitformat an, in das wir dateseit der Epoche Daten einspeisen können , um sie in Sekunden zu konvertieren. Dann vergleichen wir das einfach mit der aktuellen Zeit.

#!/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
Bis auf weiteres angehalten.
quelle
0

Ich habe die Antwort geändert, die sie dir im vorherigen Beitrag gegeben haben

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

Der reguläre Ausdruck sucht nach zwei Arten von zweiten Argumenten:

  • Tage in Form von Ziffern und einem Minuszeichen.
  • Hours:minutes:seconds Ausdruck.

Das sollte zu allem passen, außer zu jungen Prozessen, die die Form hätten minutes:seconds.

LatinSuD
quelle
Alternativ könnten wir versuchen, es so zu machen, wie PS es macht. Subtrahieren Sie das erste Argument von / proc / uptime vom 22. Argument von / proc / * / stat.
LatinSuD
0

Das ist wahrscheinlich übertrieben, aber ich wurde neugierig genug, um es zu beenden und zu testen, ob es funktioniert (natürlich mit einem anderen Prozessnamen auf meinem System). Sie können die Erfassung von $userund $pidbeenden, um die reguläre Ausdrucksweise zu vereinfachen, die ich nur zum Debuggen hinzugefügt habe und die keine Lust hatte, sie wieder zu entfernen. Benannte Captures von Perl 5.10 würden ein paar Zeilen mehr abschneiden, aber dies sollte auf älteren Perls funktionieren.

Sie müssen den Ausdruck natürlich durch einen Kill ersetzen, aber ich wollte eigentlich nichts auf meinem eigenen System töten.

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

Ich habe einen Server mit falschen Daten in / proc und find funktioniert nicht. Deshalb habe ich folgendes Skript geschrieben:

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

Python-Version mit der Uhrzeit der Prozesseinträge 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
Eduardo Ivanec
quelle
0

Ich benutze dieses einfache Skript, es dauert zwei Argumente Name des Prozesses und Alter in Sekunden.

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

das sollte funktionieren

killall --older-than 1h $proc_name

Jabir Ahmed
quelle
1
Wie kann dies [die bereits vorhandenen Antworten] ergänzen oder verbessern?
Reaces
2
@Reaces: Um ehrlich zu sein, musste ich nach der einen Antwort suchen --older-than und es ist leicht zu übersehen. Im Vergleich zu den anderen Antworten ist dies viel einfacher und jetzt auch auf EL7 verfügbar.
Sven
@Reaces dies macht es einfach einfacher als das Schreiben von Skripten mit awk / sed usw., um einen Prozess zu beenden. Ich nehme an, dies ist viel einfacher und sauberer
Jabir Ahmed
0

Ich war mit der anderen Lösung nicht zufrieden, die meisten von ihnen sind zu kryptisch (mein Bash-Wissen ist irgendwie begrenzt) und daher kann ich sie nicht anpassen ...
Ich habe meine eigene Lösung erstellt. Es ist wahrscheinlich nicht die beste, aber es funktioniert und es ist lesbar

Sie können dieses Skript in einer Datei speichern und ausführbar machen (eventuell mit cron aufrufen)

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

72 = 3 Tage 48 = 2 Tage 24 = 1 Tag

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

Es klappt :)

Onkar
quelle
1
Das mag gut sein, aber es ist ziemlich schwierig zu lesen und daraus zu lernen. Erwägen Sie eine Neuformatierung mit einigen Zeilenumbrüchen und Ähnlichem ... Skripte sind für Anweisungen besser als Einzeiler.
Falcon Momot