Jak zabić procesy starsze niż „t”?

14

Po pierwsze, tak, widziałem to pytanie:

Znajdź (i zabij) stare procesy

Odpowiedzi tam są niepoprawne i nie działają. Głosowałem i skomentowałem odpowiednio.

Procesy, które chcę zabić, wyglądają tak, gdy są wymienione na liście 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 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 Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py

Chcę skonfigurować prosty codzienny cron, który znajdzie i zabije wszelkie page.pyprocesy starsze niż godzina.

Przyjęta odpowiedź na powyższe pytanie nie działa, ponieważ nie pasuje do zakresu czasów, po prostu pasuje do procesów, które działały od 7 dni do 7 dni 23 godzin 59 minut i 59 sekund. Nie chcę zabijać procesów trwających od 1 do 2 godzin, ale raczej cokolwiek dłuższego niż 1 godzina.

Inna odpowiedź na powyższe pytanie findnie działa, przynajmniej nie w Gentoo lub CentOS 5.4, albo wyrzuca ostrzeżenie, albo nic nie zwraca, jeśli zastosowana zostanie rada wspomnianego ostrzeżenia.

hobodave
źródło

Odpowiedzi:

22

GNU Killall może zabijać procesy starsze niż określony wiek, używając swojej nazwy procesu.

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h page.py;fi
Jodie C.
źródło
1
Ta opcja nie jest dostępna w CentOS 6.6. Wersja: killall (PSmisc) 22.6.
Onnonim
9

Dzięki odpowiedzi Christophera mogłem dostosować ją do następujących kwestii:

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

-mmin było polecenie szukania, którego mi brakowało.

hobodave
źródło
3
Nie jestem pewien, czy -mmin nadaje się do wykrywania wieku procesu.
LatinSuD
Nie wygląda na to, żeby katalogi / proc / były bardzo modyfikowane, więc wydaje się, że to działa. Biorąc to pod uwagę, nie chciałbym twierdzić, że to niemożliwe.
Christopher Karel,
Nie sądzę, że to odpowiada na twoje pytanie, ponieważ ta odpowiedź jest zbyt wąska, a pytanie szersze.
poige
I powiedziałbym jeszcze więcej - to w ogóle nie działa: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init nie znajduje się na liście, pomimo czasu przestojów dla dni, a nie godzin. Wygląda na to, że nie możesz polegać na czasie modyfikacji katalogów / proc /.
poige
3
Niestety nie można na tym polegać od znaczników czasu w / proc. Przynajmniej już nie.
dpk
8

find nie zawsze działa, nie każdy system ma dostępne etime i może to być mój status regex newb, ale nie sądzę, że potrzebujesz czegoś więcej:

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • wymień wszystkie procesy i podaj kolumny PID, ELAPSED (etimes = sekundy), COMMAND, USER, TT (dzięki @ahoffman)
  • z awk wypisuje PID, w którym 4. kolumna (4 USD, USER) zawiera tekst „konstruktora”, a 5 kolumna (5 USD, TT) zawiera tekst „pts”, a kolumna ELAPSED ma wartość większą niż 600 sekund (dzięki @amtd)

następnie możesz skazać go na zabicie lub cokolwiek innego może być potrzebne.

eugenevd
źródło
Myślę, że jest to jedno z bardziej niezawodnych rozwiązań, szczególnie jeśli chodzi o użycie ps, ale złożyłbym wiele greps w jeden awk, i ze względów bezpieczeństwa ograniczyłem dopasowania wzorca do poszczególnych kolumn (aby wykluczyć np. Dopasowanie nazwy polecenia builder itp.)
jmtd
Jest to w porządku, gdy zakres czasu jest w dniach, ale nie zadziała, jeśli chcesz przetestować upływ czasu w godzinach, minutach lub sekundach.
Vlastimil Ovčáčík
użyj „etimes” zamiast „etime”, zwróci to upływ czasu w sekundach, co jest znacznie łatwiejsze do przeanalizowania.
ahofmann
@jmtd & ahofmann: Zaktualizowałem zgodnie z Twoim komentarzem. Mam nadzieję, że jest to zgodne z zamierzeniami
eugenevd
5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Jeśli chcesz, możesz karmić psz listą PID-ów do wyszukiwania, na przykład:

ps h -O etimes 1 2 3
poige
źródło
2
etimesdziała tylko dla nowszychps
Tino
4

Myślę, że możesz zmodyfikować niektóre z poprzednich odpowiedzi, aby dopasować je do swoich potrzeb. Mianowicie:

dla PLIKU w (znajdź. -maxdepth 1 -user procesuser użytkownika -typ d -mmin +60)
  do kill -9 $ (basename $ FILE) # Nigdy nie mogę zmusić basename do pracy z exec'em find. Daj mi znać, jeśli wiesz jak!
gotowy

Lub

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

Myślę, że drugi może najlepiej pasować do twoich potrzeb. Wersja znalezienia skończyłaby się nukowaniem innych procesów przez tego użytkownika


- Christopher Karel

Christopher Karel
źródło
7
Nie używaj, kill -9chyba że w ostateczności. Użyj -SIGINTlub -SIGTERM.
Wstrzymano do odwołania.
Wykorzystuje format czasu, który upłynął, jako kryterium testu, a nie jego wartość. pswyśle ​​czas w ^..:..$formacie, gdy jest on krótszy niż godzina.
Vlastimil Ovčáčík
4
apt-get install psmisc

killall -o 1h $proc_name
Alex
źródło
Czy mógłbyś pomóc wyjaśnić więcej na temat psmiscnarzędzia? OP wspomniał o CentOS; czy jest dostępny jako RPM?
Castaglia
4

Problem

Konwertowanie etime(upływający czas) kolumny pspolecenia na sekundy. Specyfikacja czasu jest w tym formacie [[dd-]hh:]mm:ss. Nowsze wersje psmają etimeskolumnę, która wyświetla etimewartość w sekundach.

Rozwiązanie: prosta niestandardowa funkcja awk

Funkcja ta awk obsługuje wszystkie formaty etimekolumnie (np 03-12:30:59, 00:07etc.). Wystarczy wkleić go do skryptu awk, jest to rozwiązanie przyjazne dla jednej linii.

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) konwertuje T na sekundy
  • Tspecyfikacja czasu w [[dd-]hh:]mm:ssformacie (np. etime)
  • Cliczba pól w T(równoważne zmiennej NF awk)
  • Atablica pól w T(odpowiednik zmiennej $ awk)
  • A[C>3?C-3:99]jest to bezpieczny sposób na odniesienie się do czwartej wartości (tj. liczby dni) w odwrotnej kolejności. Takie podejście jest przydatne, ponieważ dni i godziny są opcjonalne. Jeśli tablica nie jest wystarczająco długa, dereferencja A[99]da 0wartość. Zakładam, że 99jest wystarczająco wysoki dla większości przypadków użycia.
  • zwraca sekundy jako liczbę całkowitą

Przykład z prawdziwego świata

Ten bash oneliner zabije soffice.binproces działający pod bieżącym użytkownikiem, jeśli proces ten jest starszy niż 180 sekund.

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
źródło
1
DUŻO lepiej niż inne odpowiedzi. obsługuje również wiele proc.
Denny Weinberg,
Lepiej byłoby umieścić „polecenie” lub „argumenty” na końcu listy formatu „ps”, aby móc grepować na pełnym ciągu polecenia / args. Umieszczenie go na początku spowoduje, że ps skróci dłuższe polecenia.
Maksym
1

lstartPola w psdaje spójny format czasu, który możemy karmić się dateprzekonwertować sekund od epoki. Następnie po prostu porównujemy to z obecnym czasem.

#!/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
Wstrzymano do odwołania.
źródło
0

Zmodyfikowałem odpowiedź, którą ci dali w poprzednim poście

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

Wyrażenie regularne wyszukuje 2 typy drugiego argumentu:

  • Dni w postaci cyfr i znaku minus.
  • Hours:minutes:seconds wyrażenie.

To powinno pasować do wszystkiego oprócz młodych procesów, które miałyby formę minutes:seconds.

LatinSuD
źródło
Alternatywnie możemy spróbować zrobić to tak, jak robi to PS. Odejmij pierwszy argument / proc / uptime z 22. argumentu / proc / * / stat.
LatinSuD
0

Jest to prawdopodobnie przesada, ale zainteresowałem się na tyle, aby go zakończyć i przetestować, czy działa (oczywiście pod inną nazwą procesu w moim systemie). Możesz zabić przechwytywanie $useri $piduprościć wyrażenie regularne, które dodałem tylko do debugowania i nie miałem ochoty wycofywać się. Nazwane przechwytywanie z perla 5.10 zgoliłoby jeszcze kilka linii, ale to powinno działać na starszych perlach.

Oczywiście musisz zastąpić wydruk zabiciem, ale tak naprawdę nie miałem zamiaru niczego zabijać w moim systemie.

#!/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
źródło
0

Mam serwer z nieprawidłowymi datami w / proc i find nie działa, więc napisałem ten skrypt:

#!/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
źródło
0

Wersja Python wykorzystująca ctime wpisów procesu w /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
źródło
0

Używam tego prostego skryptu, który wymaga dwóch argumentów: nazwa procesu i wiek w sekundach.

#!/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
źródło
0

to powinno działać

killall --older-than 1h $proc_name

Jabir Ahmed
źródło
1
Jak to dodaje lub ulepsza [już istniejące odpowiedzi]?
Reaces 12.10.15
2
@Reaces: Szczerze mówiąc, musiałem znaleźć jedną odpowiedź, która wspomina --older-than i łatwo ją przeoczyć. W porównaniu z innymi odpowiedziami jest to o wiele łatwiejsze i jest teraz dostępne również na EL7.
Sven
@ Usuwa to po prostu ułatwia pisanie skryptów przy użyciu awk / sed itp. W celu zabicia procesu, to, jak sądzę, jest znacznie prostsze i czystsze
Jabir Ahmed
0

Nie byłem usatysfakcjonowany innym rozwiązaniem, większość z nich jest zbyt tajemnicza (moja wiedza na temat bash jest trochę ograniczona), więc nie mogę ich dostosować ...
Stworzyłem własne rozwiązanie. Prawdopodobnie nie jest najlepsze, ale działa i jest czytelny

Możesz zapisać ten skrypt w pliku i ustawić go jako wykonywalny (ewentualnie wywołać go za pomocą crona)

#!/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
źródło
-2

72 = 3 dni 48 = 2 dni 24 = 1 dzień

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

to działa :)

onkar
źródło
1
To może być, ale trudno jest czytać i uczyć się od nich. Zastanów się nad sformatowaniem niektórych nowych linii i innych rzeczy ... skrypty są lepsze niż instrukcje jednowierszowe.
Falcon Momot,