Bagaimana cara saya membunuh proses yang lebih tua dari "t"?

14

Pertama, ya saya telah melihat pertanyaan ini:

Temukan (dan bunuh) proses lama

Jawabannya ada yang salah dan tidak berfungsi. Saya telah memilih dan berkomentar sesuai.

Proses yang ingin saya bunuh terlihat seperti ini ketika terdaftar dengan 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

Saya ingin menyiapkan cron harian sederhana yang akan menemukan dan membunuh page.pyproses yang lebih lama dari satu jam.

Jawaban yang diterima pada pertanyaan yang disebutkan di atas tidak berfungsi, karena tidak cocok dengan rentang waktu, hanya cocok dengan proses yang telah berjalan dari 7 hari hingga 7 hari, 23 jam 59 menit dan 59 detik. Saya tidak ingin membunuh proses yang telah berjalan dari 1-2 jam, tetapi lebih dari 1 jam.

Jawaban lain untuk pertanyaan yang disebutkan di atas menggunakan findtidak berfungsi, setidaknya tidak pada Gentoo atau CentOS 5.4, itu juga memuntahkan peringatan, atau tidak mengembalikan apa pun jika saran dari peringatan tersebut diikuti.

hobodave
sumber

Jawaban:

22

GNU Killall dapat membunuh proses yang lebih tua dari usia tertentu, menggunakan nama prosesnya.

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h page.py;fi
Jodie C
sumber
1
Opsi itu tidak tersedia di CentOS 6.6. Versi: killall (PSmisc) 22.6.
Onnonymous
9

Berkat jawaban Christopher, saya dapat menyesuaikannya dengan yang berikut:

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

-mmin adalah perintah find yang saya lewatkan.

hobodave
sumber
3
Tidak yakin apakah -mmin cocok untuk mendeteksi usia suatu proses.
LatinSuD
Tampaknya direktori / proc / tidak banyak dimodifikasi, jadi ini sepertinya berhasil. Yang sedang berkata, saya tidak ingin mengklaim itu tidak mungkin.
Christopher Karel
Saya tidak berpikir ini menjawab pertanyaan Anda karena jawaban ini terlalu sempit dan pertanyaan lebih luas.
poige
Dan saya akan mengatakan lebih - itu tidak bekerja sama sekali: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init tidak terdaftar meskipun hitungan uptime berhari-hari, bukan jam. Tampaknya Anda tidak dapat mengandalkan waktu modifikasi dir / proc /.
poige
3
Stempel waktu di / proc tidak dapat diandalkan untuk ini, sayangnya. Setidaknya tidak lagi.
dpk
8

temukan tidak selalu berfungsi, tidak setiap sistem memiliki etimes yang tersedia, dan itu mungkin status regex newb saya, tapi saya rasa Anda tidak perlu lebih dari ini:

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • daftar semua proses dan sediakan kolom PID, TERGANTUNG (etimes = detik), PERINTAH, PENGGUNA, TT (terima kasih @ahoffman)
  • dengan awk, cetak PID di mana kolom ke-4 ($ 4, USER) berisi teks 'builder', dan kolom ke-5 ($ 5, TT) berisi teks 'pts' dan kolom ELAPSED memiliki nilai lebih besar dari 600 detik (terima kasih @amtd)

Anda kemudian dapat pipa itu untuk membunuh atau apa pun kebutuhan Anda.

eugenevd
sumber
Saya pikir ini adalah salah satu solusi yang lebih kuat, terutama dalam hal penggunaan Anda ps, tetapi saya akan melipat beberapa greps menjadi satu awk, dan untuk keamanan membatasi pencocokan pola ke kolom tertentu (untuk mengesampingkan misalnya pencocokan nama perintah builder, dll.)
jmtd
Ini bagus ketika ruang lingkup Anda dalam berhari-hari, tetapi tidak akan berfungsi jika Anda ingin menguji waktu yang telah berlalu dalam jam, menit atau detik.
Vlastimil Ovčáčík
gunakan "etimes" alih-alih "etime", ini akan mengembalikan waktu yang telah berlalu dalam hitungan detik yang jauh lebih mudah diurai.
ahofmann
@ jmtd & ahofmann: Saya telah memperbarui sesuai komentar Anda. Saya harap ini seperti yang Anda maksudkan
eugenevd
5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Jika mau, Anda dapat memberi makan psdengan daftar PID untuk dicari di dalamnya, misalnya:

ps h -O etimes 1 2 3
poige
sumber
2
etimeshanya berfungsi untuk yang lebih barups
Tino
4

Saya pikir Anda dapat mengubah beberapa dari jawaban sebelumnya yang sesuai dengan kebutuhan Anda. Yaitu:

untuk FILE dalam (temukan. -maxdepth 1 -pengguna pengguna -type d -mmin +60)
  lakukan kill -9 $ (basename $ FILE) # Saya tidak pernah bisa mendapatkan basename untuk bekerja dengan exec's find. Beri tahu saya jika Anda tahu caranya!
selesai

Atau

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

Saya pikir yang kedua paling sesuai dengan kebutuhan Anda. Versi find akan mengakhiri proses lain oleh pengguna tersebut


--Christopher Karel

Christopher Karel
sumber
7
Jangan gunakan kill -9kecuali sebagai pilihan terakhir. Gunakan -SIGINTatau -SIGTERM.
Dijeda sampai pemberitahuan lebih lanjut.
Ini menggunakan format waktu yang telah berlalu sebagai kriteria pengujian, bukan nilainya. psakan menampilkan waktu dalam ^..:..$format ketika kurang dari satu jam.
Vlastimil Ovčáčík
4
apt-get install psmisc

killall -o 1h $proc_name
Alex
sumber
Bisakah Anda membantu menjelaskan lebih lanjut tentang psmiscutilitas ini? OP menyebutkan CentOS; apakah tersedia sebagai RPM?
Castaglia
4

Masalah

Mengkonversi etimekolom (waktu yang berlalu) psperintah ke detik. Spesifikasi waktu dalam format ini [[dd-]hh:]mm:ss. Versi yang lebih baru psmemiliki etimeskolom yang menampilkanetime nilai dalam hitungan detik.

Solusinya: fungsi awk kustom sederhana

Fungsi awk khusus ini mendukung semua format etimekolom (misalnya 03-12:30:59, 00:07dll.) Cukup tempel di skrip awk Anda, ini adalah solusi ramah satu-liners.

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) mengkonversi T ke detik
  • Tspesifikasi waktu dalam [[dd-]hh:]mm:ssformat (misetime )
  • Cjumlah bidang dalam T(setara dengan variabel NF awk)
  • Aarray bidang dalam T(setara dengan $ variabel awk)
  • A[C>3?C-3:99]ini cara aman untuk merujuk nilai keempat (yaitu jumlah hari) dalam urutan terbalik. Pendekatan ini bermanfaat karena hari dan jam adalah opsional. Jika array tidak cukup panjang itu dereference A[99]yang akan menghasilkan 0nilai. Saya berasumsi 99cukup tinggi untuk sebagian besar kasus penggunaan.
  • mengembalikan detik sebagai integer

Contoh dunia nyata

Bash oneliner ini akan mematikan soffice.binproses yang berjalan di bawah pengguna saat ini jika prosesnya lebih dari 180 detik.

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
sumber
1
JAUH lebih baik bahwa jawaban lainnya. ini juga menangani multi procs.
Denny Weinberg
Akan lebih baik untuk menempatkan 'command' atau 'args' di akhir daftar format 'ps' untuk dapat memahami string perintah / args penuh. Menempatkannya di awal akan menyebabkan ps memotong perintah yang lebih panjang.
Maksym
1

The lstartlapangan di psmemberikan format waktu yang konsisten yang kita dapat memberi makan untuk dateuntuk mengkonversi ke detik sejak zaman tersebut. Kemudian kita membandingkannya dengan waktu sekarang.

#!/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
Dijeda sampai pemberitahuan lebih lanjut.
sumber
0

Saya mengubah jawaban yang mereka berikan pada posting sebelumnya

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

Ekspresi reguler mencari 2 jenis argumen kedua:

  • Hari dalam bentuk digit dan tanda minus.
  • Hours:minutes:seconds ekspresi.

Itu harus cocok dengan segala sesuatu kecuali proses muda yang akan memiliki formulir minutes:seconds.

LatinSuD
sumber
Atau kita dapat mencoba melakukannya dengan cara PS melakukannya. Kurangi argumen pertama dari / proc / uptime dari argumen ke-22 dari / proc / * / stat.
LatinSuD
0

Ini mungkin berlebihan, tetapi saya cukup penasaran untuk menyelesaikannya dan mengujinya bekerja (pada nama proses yang berbeda pada sistem saya, tentu saja). Anda dapat membunuh penangkapan $userdan $piduntuk menyederhanakan regexp, yang saya hanya tambahkan untuk debugging, dan tidak merasa ingin merobek kembali. Bernama menangkap dari perl 5.10 akan mencukur beberapa baris lagi, tetapi ini harus bekerja pada perl yang lebih tua.

Anda harus mengganti cetakan dengan kill, tentu saja, tetapi saya tidak akan benar-benar membunuh apa pun di sistem saya sendiri.

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

Saya memiliki server dengan tanggal yang salah di / proc dan ternyata tidak berfungsi, jadi saya menulis skrip ini:

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

Versi python menggunakan ctime dari entri proses di /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
sumber
0

Saya menggunakan skrip sederhana ini butuh dua argumen nama proses dan umur dalam hitungan detik.

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

ini seharusnya bekerja

killall --older-than 1h $proc_name

Jabir Ahmed
sumber
1
Bagaimana cara ini menambah atau meningkatkan [jawaban yang sudah ada]?
Reaces
2
@Reaces: Dalam semua keadilan, saya harus mencari satu jawaban yang menyebutkan --older-than dan mudah untuk mengabaikannya. Dibandingkan dengan jawaban lain, ini jauh lebih mudah, dan sekarang tersedia di EL7.
Sven
@Reaces ini hanya membuatnya lebih mudah daripada menulis skrip menggunakan awk / sed dll untuk membunuh suatu proses, ini saya kira jauh lebih sederhana dan bersih
Jabir Ahmed
0

Saya tidak puas dengan solusi yang lain, kebanyakan dari mereka terlalu samar (pengetahuan bash saya agak terbatas) dan jadi saya tidak dapat menyesuaikannya ...
Saya telah membuat solusi sendiri, Mungkin bukan yang terbaik tetapi berfungsi dan itu bisa dibaca

Anda dapat menyimpan skrip ini dalam file dan membuatnya dapat dieksekusi (akhirnya menyebutnya dengan menggunakan cron)

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

72 = 3 hari 48 = 2 hari 24 = 1 hari

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

berhasil :)

onkar
sumber
1
Mungkin memang begitu, tetapi cukup sulit untuk membaca dan belajar darinya. Pertimbangkan memformat ulang dengan beberapa baris baru dan yang lainnya ... skrip lebih baik daripada instruksi satu baris.
Falcon Momot