你如何杀死所有超过一定年龄的Linux进程?

时间:2008-08-08 16:50:47

标签: linux bash unix process

我在某个服务器上遇到类似僵尸的进程有问题需要时不时地被杀死。如何才能最好地识别运行时间超过一小时的那些?

14 个答案:

答案 0 :(得分:36)

找到一个适合我的答案:

警告:这会找到并杀死长时间运行的进程

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

(其中 user-id 是具有长时间运行流程的特定用户ID。)

第二个正则表达式匹配具有可选天数的时间,后跟小时,分钟和秒组件,因此至少有一个小时。

答案 1 :(得分:30)

如果他们只是需要被杀:

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

如果你想看看它匹配什么

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

-i标志将为每个进程匹配提示您是/否。

答案 2 :(得分:22)

对于任何超过一天的事情,

ps aux

会给你答案,但它会降低到日精度,这可能没那么有用。

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]

如果您使用的是/ proc文件系统的Linux或其他系统,在此示例中,您只能看到进程1自6月22日以来一直在运行,但没有指示它的启动时间。

stat /proc/<pid>

会给你一个更准确的答案。例如,这是进程1的确切时间戳,ps仅显示为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

答案 3 :(得分:9)

通过这种方式,您可以获得十个最古老的流程列表:

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

答案 4 :(得分:8)

Jodie C和其他人已经指出可以使用killall -i,如果你想使用进程名称来杀死它就没问题了。但是如果你想通过与pgrep -f相同的参数来杀死,你需要使用类似下面的东西,使用纯bash和/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     

这使您可以使用完整进程名称查找并终止超过max_age秒的进程;即,名为/usr/bin/python2 offlineimap的进程可以通过引用“offlineimap”来终止,而此处提供的killall解决方案仅适用于字符串“python2”。

答案 5 :(得分:7)

Perl的Proc :: ProcessTable可以解决这个问题: http://search.cpan.org/dist/Proc-ProcessTable/

您可以使用sudo apt-get install libproc-processtable-perl

在debian或ubuntu中安装它

这是一个单行:

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

或者,格式化更多,将其放在名为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";
    }
}

然后运行perl process.pl

这为您提供了更多的多功能性和1秒的开始时间分辨率。

答案 6 :(得分:3)

你可以使用bc加入暴徒答案中的两个命令,并获取自进程开始以来已经过了多少秒:

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

编辑:

在等待漫长的进程运行时出于无聊,这是几分钟后摆弄的结果:

#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

如果你把它放在路径上并像这样调用它:    从那时起

它将打印自启动以来的进程cmdline和秒。您也可以将它放在您的路径中:

#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

而不是你跑:

greptime <pattern>

其中patterns是字符串或扩展正则表达式,它将打印出与此模式匹配的所有进程以及自启动以来的秒数。 :)

答案 7 :(得分:2)

做一个ps -aef。这将显示进程开始的时间。然后使用date命令查找当前时间。计算两者之间的差异,找出过程的年龄。

答案 8 :(得分:1)

我做了类似于接受的答案,但略有不同,因为我希望根据流程名称和基于运行时间超过100秒的错误流程进行匹配

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

答案 9 :(得分:1)

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

从纪元开始以秒为单位获取过程的开始时间。与当前时间(date +%s)比较以获得流程的当前年龄。

答案 10 :(得分:0)

使用ps是正确的方法。我之前已经做过类似的事情,但没有方便的来源。 通常 - ps可以选择告诉它要显示哪些字段以及要对哪些字段进行排序。您可以通过运行时间对输出进行排序,grep您想要的进程然后将其终止。

HTH

答案 11 :(得分:0)

如果有人在C中需要这个,你可以使用readproc.h和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;
}

答案 12 :(得分:0)

来到某个地方......认为这很简单实用

您可以直接在crontab中使用该命令,

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

或者,我们可以把它写成shell脚本,

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

并像这样称呼crontab,

* * * * * longprockill.sh

答案 13 :(得分:0)

@Rafael S. Calsaverini的上述sincetime版本:

#!/bin/bash
ps --no-headers -o etimes,args "$1"

这将反转输出字段:首先是经过时间,第二是包括参数的完整命令。这是首选,因为full命令可能包含空格。