如何杀死所有超过某个年龄的Linux进程?

如何杀死所有超过某个年龄的Linux进程?,linux,bash,unix,process,Linux,Bash,Unix,Process,我对某个服务器上的一些类似僵尸的进程有一个问题,需要时不时地杀死它们。如何才能最好地识别运行时间超过一个小时左右的设备?使用ps是正确的方法。我以前也做过类似的事情,但是没有现成的资料。 通常-ps有一个选项告诉它显示哪些字段以及按哪些字段排序。您可以通过运行时间对输出进行排序,grep您想要的进程,然后终止它 HTH对于任何超过一天的事件 ps aux 将为您提供答案,但它会降低到日精度,这可能没有那么有用 USER PID %CPU %MEM VSZ RSS TTY

我对某个服务器上的一些类似僵尸的进程有一个问题,需要时不时地杀死它们。如何才能最好地识别运行时间超过一个小时左右的设备?

使用ps是正确的方法。我以前也做过类似的事情,但是没有现成的资料。 通常-ps有一个选项告诉它显示哪些字段以及按哪些字段排序。您可以通过运行时间对输出进行排序,grep您想要的进程,然后终止它


HTH

对于任何超过一天的事件

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]
如果您在linux或另一个带有/proc文件系统的系统上,在本例中,您只能看到进程1自6月22日以来一直在运行,但没有显示它的启动时间

stat /proc/<pid>

找到了一个适合我的答案:

警告:这将查找并终止长时间运行的进程

ps -eo uid,pid,etime | egrep '^ *user-id' | egrep ' ([0-9]+-)?([0-9]{2}:?){3}' | awk '{print $2}' | xargs -I{} kill {}
(其中用户id是具有长时间运行的进程的特定用户id。)


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

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

ps -elf | sort -r -k12 | head -n 10
ps-elf | sort-r-k12 | head-n10do a
ps-aef
。这将显示进程开始的时间。然后使用
date
命令查找当前时间。计算两者之间的差异,找出进程的时间。

Perl的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" } }'
perl-MProc::ProcessTable-Mstrict-w-e'my$anHourAgo=time-60*60;my$t=新的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";
    }
}
#/usr/bin/perl-w
严格使用;
使用Proc::ProcessTable;
my$anHourAgo=时间-60*60;
my$t=新的Proc::ProcessTable;
foreach my$p(@{$t->table}){
如果($p->start()<$anHourAgo){
打印$p->pid,“\n”;
}
}
然后运行
perl进程.pl


这为您提供了更多的通用性和1秒的启动时间分辨率。

我做了一些类似于公认答案的事情,但略有不同,因为我希望根据进程名称和运行超过100秒的坏进程进行匹配

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


获取自历元以来进程的开始时间(以秒为单位)。与当前时间(
date+%s
)进行比较,以获取进程的当前时间。

如果有人需要使用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;
}
#包括
#包括
浮动
pid_年龄(pid_t pid)
{
过程信息;
自启动以来的整数秒=正常运行时间(0,0);
如果(!获取进程统计信息(pid和进程信息)){
返回0.0;
}
//readproc.h的评论对proc\u t.start\u时间是什么撒谎。它是
//自启动以来,实际以赫兹刻度表示
自1970年以来的整数秒=时间(空);
int time_of_boot=自_1970年起的秒数-自_boot起的秒数;
长t=自启动后的秒数-(无符号长)(proc\u info.start\u time/Hertz);
int delta=t;
浮动天数=((浮动)增量/(浮动)(60*60*24));
返程天数;
}

如果只需要杀死他们:

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi
如果你想看看它匹配什么

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

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

您可以使用
bc
将mob的答案中的两个命令连接起来,并获得流程启动后的等待时间:

echo `date +%s` - `stat -t /proc/<pid> | awk '{print $14}'` | bc
如果你把它放在你的路径上,并这样称呼它: 从那时起

它将打印流程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>
greptime

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

Jodie C和其他人已经指出可以使用
killall-i
,如果您想使用进程名来kill,这很好。但是,如果您想使用与
pgrep-f
相同的参数进行kill,则需要使用以下类似的东西,使用纯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
秒的进程;i、 例如,名为
/usr/bin/python2 offlineimap
的进程可以通过引用“offlineimap”来终止,而这里介绍的
killall
解决方案只对字符串“python2”起作用。

在某个地方遇到过。虽然它简单而有用

您可以直接使用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

@Rafael S.Calsaverini的《我的自那时以来的<代码>版本》

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

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

好提示。后来我偶然发现了--older-than开关,但是-I使它在杀死谁知道是什么之前的检查非常有用?相关部分不是只有
killall
命令吗?(似乎可以删除周围的
if
子句,使答案更直接一些)@ringo,因为在某些系统(例如Solaris)上,killall是一个完全不同的命令。在Solaris上,它终止所有命令。请注意,使用killall的'--regex'选项会导致'--older than'被忽略。快乐我们可以将两个命令合并,以获得进程启动后的秒数:
* * * * * longprockill.sh
#!/bin/bash
ps --no-headers -o etimes,args "$1"