Cum ucizi toate procesele Linux care sunt mai vechi decât o anumită vârstă?

Am o problemă cu unele procese asemănătoare cu zombie pe un anumit server care trebuie să fie ucis din când în când. Cum pot identifica cel mai bine cele care au rulat mai mult de o oră?

0
fr hi bn
Sau puteți vedea răspunsul meu care utilizează pgrep și este deci mai flexibil decât killall .
adăugat autor g33kz0r, sursa
În Linux, folosiți killall -i --older-decât 1h someprocessname
adăugat autor sanmai, sursa

13 răspunsuri

Pentru orice mai mult de o zi,

ps aux

vă va da răspunsul, dar scade până la precizia zilnică, care nu ar putea fi la fel de utilă.

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]

Dacă sunteți pe linux sau un alt sistem cu sistemul de fișiere / proc, în acest exemplu, puteți vedea numai că procesul 1 a fost difuzat începând cu 22 iunie, dar nici o indicație a timpului în care a fost pornit.

stat /proc/

vă va da un răspuns mai precis. De exemplu, aici este un timbru exact pentru procesul 1, care ps se afișează doar ca Jun22:

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
adăugat
De asemenea, am să notez că, dacă procesul a fost început în anul precedent, coloana START afișează doar anul. Nu prea multă precizie. deloc. Pe langa asta, cand am stat proc o idul unei sesiuni tmux de lunga durata din anul trecut, a raportat o data din acest an. Soluție am mers cu: ps -eo pid, etime | grep $ PID
adăugat autor Steven Lu, sursa
Se pare că ps și stat prezintă rezultate diferite pentru mine. ps arată că procesul a început acum o zi și stat arată că a început astăzi. De ce?
adăugat autor pl1nk, sursa
Rețineți că coloana TIME din ieșirea ps nu indică timpul efectiv de rulare al unui proces. Acesta arată timpul CPU acumulat al procesului - timpul pe care CPU-ul a funcționat-o cu procesul.
adăugat autor matthias krull, sursa
mulțumesc, stat / proc / mi-a dat rezultatul exact pentru durata de viață a procesului (timpul de pornire)
adăugat autor baptx, sursa

În acest fel puteți obține lista celor zece cele mai vechi procese:

ps -elf | sort -r -k12 | head -n 10
0
adăugat
De fapt, aceasta vă oferă cele mai recente 10 procese deoarece, în mod implicit, arată STIME, care este momentul în care programul a început. Dacă ar fi arătat ETIME care este timpul scurs de la începerea programului, atunci aceasta ar fi corectă.
adăugat autor Sarel Botha, sursa
chestii bune, mulțumesc pentru asta.
adăugat autor donovan.lampa, sursa

Folosirea lui ps este cea corectă. Am mai făcut ceva similar înainte, dar nu am sursa la îndemână. În general - ps are opțiunea de a spune care câmpuri să fie afișate și prin care să se sorteze. Puteți sorta ieșirea prin timpul de funcționare, grepați procesul dorit și apoi îl puteți omorî.

HTH

0
adăugat

S-a găsit un răspuns care funcționează pentru mine:

avertisment: acesta va găsi și ucide procesele de lungă durată

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

(Unde user-id este un ID de utilizator specific cu procese de lungă durată.)

A doua expresie regulată se potrivește cu o perioadă care are o cifră opțională de zile, urmată de o oră, minut și de a doua componentă, deci are o lungime de cel puțin o oră.

0
adăugat
@ButtleButkus Bun punct. Da, întregul motiv pentru această întrebare a fost acela de a găsi vechile procese și de a le ucide, dar nu se menționează în mod explicit acest lucru clar. Notați altora: ignorați ultimul pic de linie dacă nu vă bucurați de apeluri supărătoare de la utilizatori.
adăugat autor yukondude, sursa
@ Marki555 care pare a fi doar biletul. Trebuie să fie într-o versiune mai recentă a PS-ului pe care o conduc, totuși, deoarece nu este listată ca o opțiune.
adăugat autor yukondude, sursa
Uh, ucizi procesul? Sper că oamenii își dau seama că acest cod nu găsește doar, ci și ucide, sau ar putea fi supărați.
adăugat autor Buttle Butkus, sursa
Puteți utiliza opțiunea etimes în loc de etime pentru a afișa întotdeauna timpul scurs în secunde și nu zile / ore ...
adăugat autor Marki555, sursa
@yukondude ai dreptate. Tocmai am verificat-o și ps v3.2.8 din debian squeeze nu suportă parametrul etimes , dar versiunea v3.3.3 de la wheezy debian face.
adăugat autor Marki555, sursa
WTF! modificați titlul întrebării. Din fericire nu am propriul proces!
adăugat autor neal aise, sursa

Puteți utiliza bc pentru a vă alătura celor două comenzi din răspunsul mulțimii și pentru a obține câte secunde a eșuat de la începerea procesului:

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

Editați | ×:

Din plictiseala in timp ce asteptau procese lungi de rulare, asta a aparut dupa cateva minute de mana:

#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

Dacă puneți acest lucru pe calea voastră și spuneți-l astfel:    sincetime

se va imprima cmdline-ul procesului și secundele de la pornire. Puteți, de asemenea, pune acest lucru în calea voastră:

#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

Și decât dacă alergi:

greptime 

unde modelele sunt un șir sau o expresie regulată extinsă, aceasta va tipări toate procesele care se potrivesc cu acest șablon și secundele de la pornire. :)

0
adăugat

Perl's Proc::ProcessTable will do the trick: http://search.cpan.org/dist/Proc-ProcessTable/

You can install it in debian or ubuntu with sudo apt-get install libproc-processtable-perl

Aici este un singur liner:

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

Sau, formatat mai mult, pune acest lucru într-un fișier numit process.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";
    }
}

then run perl process.pl

Acest lucru vă oferă mai multă versatilitate și o rezoluție de 1 secundă la ora de începere.

0
adăugat

Jodie C și alții au subliniat că killall -i poate fi folosit, ceea ce este bine dacă doriți să utilizați numele procesului pentru a ucide. Dar dacă doriți să o omorați prin aceiași parametri ca pgrep -f , trebuie să utilizați ceva asemănător, folosind bash pur și sistemul de fișiere / proc .

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

Aceasta vă permite să găsiți și să ucideți procese mai vechi de max_age secunde utilizând numele procesului complet ; adică procesul denumit / usr / bin / python2 offlineimap poate fi ucis prin trimitere la "offlineimap", în timp ce soluțiile killall prezentate aici vor funcționa numai pe șirul "python2 “.

0
adăugat

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

pentru a obține timpul de începere al procesului în câteva secunde de la epocă. Comparați cu ora curentă ( date +% s ) pentru a obține vârsta curentă a procesului.

0
adăugat
Putem uni două comenzi pentru a obține secunde de la începerea procesului: "echo stat -t / proc / | awk '{print $ 14}' cod> | bc "
adăugat autor Rafael S. Calsaverini, sursa
@dpk: uneori aveți un proces principal și unele furci rulează. Procesul principal ar trebui să fie 9:49, dar procesul copilului poate avea mai recent. Același lucru este valabil și pentru firele unui proces.
adăugat autor higuita, sursa

faceți un ps -aef . acest lucru vă va arăta momentul în care procesul a început. Apoi folosiți comanda date pentru a afla ora curentă. Calculați diferența dintre cele două pentru a afla vârsta procesului.

0
adăugat
Din păcate, timpul de ieșire aici este dificil de analizat. Poate fi "HH: MM" pentru procese de scurtă durată sau "MonDD" (eventual localizat!) Sau chiar doar anul pentru procese foarte lungi.
adăugat autor Slaven Rezic, sursa

Am făcut ceva similar cu răspunsul acceptat, dar puțin diferit, deoarece vreau să se potrivesc pe baza procesului și bazat pe procesul rău care rulează mai mult de 100 de secunde

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

În cazul în care cineva are nevoie de acest lucru în C, puteți folosi readproc.h și libproc:

#include 
#include 

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;
}
0
adăugat

Dacă trebuie doar să fie uciși:

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

Dacă doriți să vedeți ce se potrivește

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

Parola -i vă va solicita cu da / nu pentru fiecare meci de proces.

0
adăugat
Bun sfat. M-am lovit mai târziu de comutatorul - decât de comutator, dar -i o face utilă pentru a verifica înainte de a ucide cine știe ce.
adăugat autor yukondude, sursa
Care este punctul de dacă [["$ (uname)" = "Linux"]]; ? Nu este porțiunea relevantă doar comanda killall ? (Se pare că clauza în cazul în care ar putea fi eliminată pentru a face acest răspuns un pic mai direct)
adăugat autor rinogo, sursa
@ringo Deoarece în unele sisteme (de exemplu, Solaris), killall este o comandă complet diferită. Pe Solaris, termină toate comenzile.
adăugat autor ctc, sursa

A venit peste undeva ... cred că este simplu și util

Puteți folosi comanda în crontab direct,

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

sau, îl putem scrie ca script shell,

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

Și o numiți crontab așa,

* * * * * longprockill.sh
0
adăugat