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.

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

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.


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.


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

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


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

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

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

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.


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


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 "

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

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

0

to powinno działać

killall --older-than 1h $proc_name


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

-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 :)


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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.