2008-08-08 27 views
65

Tôi gặp vấn đề với một số quy trình giống như zombie trên một máy chủ nhất định cần phải bị giết ngay bây giờ. Làm thế nào tôi có thể xác định tốt nhất những cái đã chạy lâu hơn một giờ?Làm thế nào để bạn giết tất cả các quy trình Linux cũ hơn một độ tuổi nhất định?

+5

Trong Linux sử dụng 'killall -i --older-hơn 1h someprocessname' – sanmai

+0

Hoặc xem câu trả lời của tôi sử dụng' pgrep' và do đó linh hoạt hơn 'killall'. – g33kz0r

Trả lời

28

Nếu họ chỉ cần bị giết:

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

Nếu bạn muốn xem những gì nó có phù hợp với

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

Cờ -i sẽ nhắc bạn có/không cho mỗi quá trình khớp.

+0

Mẹo hay. Tôi vấp phải công tắc bật lửa sau này, nhưng cái -i làm cho nó hữu dụng để kiểm tra trước khi giết người biết cái gì. – yukondude

+3

Điểm của 'if [[" $ (uname) "=" Linux "]];' là gì? Không phải là phần liên quan chỉ là lệnh 'killall'? (Có vẻ như mệnh đề 'if' xung quanh có thể bị loại bỏ để làm cho câu trả lời này trực tiếp hơn) – rinogo

+0

@ringo Vì trên một số hệ thống (ví dụ Solaris), killall là một lệnh hoàn toàn khác.Trên Solaris, nó chấm dứt tất cả các lệnh. – ctc

0

Sử dụng ps là đúng cách. Tôi đã làm một cái gì đó tương tự trước nhưng không có nguồn tiện dụng. Nói chung - ps có tùy chọn để cho biết trường nào sẽ hiển thị và để sắp xếp. Bạn có thể sắp xếp đầu ra bằng cách chạy thời gian, grep quá trình bạn muốn và sau đó giết nó.

HTH

22

Đối với bất cứ điều gì lớn hơn một ngày,

ps aux 

sẽ cho bạn câu trả lời, nhưng nó giảm xuống cho đến ngày chính xác mà có thể không phải là hữu ích.

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] 

Nếu bạn đang ở trên Linux hoặc hệ thống khác với hệ thống tập tin/proc, Trong ví dụ này, bạn có thể chỉ thấy rằng quá trình 1 đã được tiến hành từ ngày 22 tháng 6, nhưng không có dấu hiệu của thời gian nó đã được bắt đầu.

stat /proc/<pid> 

sẽ cung cấp cho bạn câu trả lời chính xác hơn. Ví dụ, đây là một dấu thời gian chính xác cho quá trình 1, ps chỉ hiển thị như 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

Có vẻ như 'ps' và' stat' đang hiển thị các kết quả khác nhau cho tôi. 'ps' cho thấy rằng quá trình đã bắt đầu cách đây 1 ngày và stat cho thấy bắt đầu từ hôm nay. Tại sao? – pl1nk

+0

Lưu ý rằng cột 'TIME' trong đầu ra' ps' không hiển thị thời gian chạy thực tế của một tiến trình. Nó cho thấy thời gian CPU tích lũy của quá trình - thời gian mà CPU đã làm việc với quy trình. –

+0

Cảm ơn, stat/proc/ đã cho tôi kết quả chính xác về tuổi thọ quy trình (thời gian khởi động) – baptx

36

Tìm thấy một câu trả lời mà làm việc cho tôi:

cảnh báo: điều này sẽ tìm và giết tiến trình đang chạy dài

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

(Trong trường hợp sử dụng id là ID của người dùng cụ thể với quá trình dài chạy.)

Biểu thức chính quy thứ hai khớp với thời gian có số ngày tùy chọn, theo sau là một giờ, phút và thành phần thứ hai và có ít nhất một giờ.

+5

Umm, bạn đang giết quá trình? Tôi hy vọng mọi người nhận ra mã này không chỉ tìm thấy, mà còn giết chết, hoặc họ có thể cảm thấy khó chịu. –

+0

@ButtleButkus Điểm tốt. Vâng, toàn bộ lý do cho câu hỏi là tìm ra các quy trình cũ và giết chúng, nhưng nó không đề cập rõ ràng tất cả điều đó. Lưu ý cho người khác: bỏ qua một chút cuối cùng của dòng trừ khi bạn tận hưởng cuộc gọi tức giận từ người dùng. – yukondude

+2

wtf! hãy thay đổi tiêu đề của câu hỏi. may mắn tôi không sở hữu quá trình này! –

9

Bằng cách này bạn có thể lấy danh sách của mười quá trình lâu đời nhất:

ps -elf | sort -r -k12 | head -n 10
+0

những thứ tốt, cảm ơn vì điều này. –

+0

Thực tế là cung cấp cho bạn 10 quy trình mới nhất bởi vì theo mặc định, nó hiển thị STIME là thời gian chương trình bắt đầu. Nếu nó đã được hiển thị ETIME đó là thời gian trôi qua kể từ khi chương trình bắt đầu thì điều này sẽ là chính xác. –

2

làm một ps -aef. điều này sẽ cho bạn biết thời gian bắt đầu quá trình. Sau đó, sử dụng lệnh date tìm thời gian hiện tại. Tính toán sự khác biệt giữa hai để tìm tuổi của quá trình.

+0

Thật không may là thời gian đầu ra ở đây rất khó phân tích cú pháp. Nó có thể là "HH: MM" cho các quy trình chạy ngắn, hoặc "MonDD" (có thể được bản địa hóa!) Hoặc thậm chí chỉ là năm cho các quy trình chạy rất dài. –

7

Proc Perl :: ProcessTable sẽ làm các trick: http://search.cpan.org/dist/Proc-ProcessTable/

Bạn có thể cài đặt nó trong debian hay ubuntu với sudo apt-get install libproc-processtable-perl

Đây là một one-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" } }' 

Hoặc, được định dạng nhiều hơn, đặt nó vào một tệp gọi là quá trình.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"; 
    } 
} 

sau đó chạy perl process.pl

này cho phép bạn linh hoạt hơn và 1 giây với độ phân giải trên thời gian bắt đầu.

1

tôi đã làm một cái gì đó tương tự như câu trả lời chấp nhận nhưng hơi khác nhau kể từ khi tôi muốn để phù hợp dựa trên tên quá trình và dựa trên quá trình xấu chạy cho hơn 100 giây

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

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

để có được thời gian bắt đầu của quá trình tính bằng giây kể từ thời đại. So sánh với thời gian hiện tại (date +%s) để biết tuổi hiện tại của quy trình.

+0

Chúng ta có thể tham gia hai lệnh để lấy giây kể từ khi bắt đầu quá trình: "echo' stat -t/proc/ | awk '{print $ 14}' '-' date +% s' | bc " –

+1

Điều này sẽ không luôn luôn đúng - ít nhất là không cho các hệ thống Linux 2.6. Tôi có một quá trình bắt đầu từ 9:49 nhưng stat -t (và stat) cho thấy nó bắt đầu lúc 13:14. –

+0

@dpk: đôi khi bạn có một quy trình chính và một số dĩa chạy. Quá trình chính nên là 9:49, nhưng quá trình con có thể có thêm thời gian gần đây. Điều tương tự cũng áp dụng cho các chủ đề của một quá trình. – higuita

0

Trong trường hợp bất cứ ai cần điều này trong C, bạn có thể sử dụng readproc.h và libproc:

#include <proc/readproc.h> 
#include <proc/sysinfo.h> 

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

Bạn có thể sử dụng bc tham gia hai lệnh trong câu trả lời đám đông và được bao nhiêu giây ellapsed kể từ khi quá trình này bắt đầu:

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

chỉnh sửa:

Out of nhàm chán trong khi chờ đợi cho quá trình dài để chạy , đây là những gì xuất hiện sau vài phút không quan tâm:

#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 

Nếu bạn đặt nó trên đường dẫn và gọi nó như sau: sincetime

nó sẽ in quá trình cmdline và giây kể từ khi bắt đầu. Bạn cũng có thể đặt điều này trong đường dẫn của bạn:

#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 

Và hơn nếu bạn chạy:

greptime <pattern> 

nơi mô hình là một chuỗi hoặc mở rộng biểu hiện thường xuyên, nó sẽ in ra tất cả các quy trình phù hợp với mô hình này và giây kể từ khi họ bắt đầu. :)

7

Jodie C và những người khác đã chỉ ra rằng killall -i có thể được sử dụng, đó là tốt nếu bạn muốn sử dụng tên quy trình để giết. Nhưng nếu bạn muốn giết bởi các tham số giống như pgrep -f, bạn cần phải sử dụng một cái gì đó như sau, sử dụng bash tinh khiết và hệ thống tập tin /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  

này cho phép bạn tìm và diệt các tiến trình già hơn max_age giây bằng cách sử dụng tên quá trình đầy đủ; I E., quá trình có tên /usr/bin/python2 offlineimap có thể bị giết bằng cách tham chiếu đến "offlineimap", trong khi các giải pháp killall được trình bày ở đây sẽ chỉ hoạt động trên chuỗi "python2".

0

đi qua somewhere..thought nó là đơn giản và hữu ích

Bạn có thể sử dụng lệnh trong crontab trực tiếp,

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

hay, chúng ta có thể viết nó như shell script,

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

Và gọi nó là crontab như vậy,

* * * * * longprockill.sh 
Các vấn đề liên quan