我在某个服务器上需要不时地杀死某些类似于僵尸进程的问题。我如何最好地识别运行时间超过一个小时左右的设备?
Answers:
如果只需要杀死他们:
if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h someprocessname;fi
如果要查看它的匹配项
if [[ "$(uname)" = "Linux" ]];then killall -i --older-than 1h someprocessname;fi
该-i
标志将为每个过程匹配提示您是/否。
if [[ "$(uname)" = "Linux" ]];
?相关部分不只是killall
命令吗?(似乎if
可以删除周围的子句以使此答案更直接一些)
找到了一个对我有用的答案:
警告:这将发现并杀死长时间运行的进程
ps -eo uid,pid,etime | egrep '^ *user-id' | egrep ' ([0-9]+-)?([0-9]{2}:?){3}' | awk '{print $2}' | xargs -I{} kill {}
(其中user-id是具有长时间运行进程的特定用户的ID。)
第二个正则表达式匹配一个具有可选天数的时间,后跟一个小时,分钟和第二个部分,因此长度至少为一个小时。
etimes
而不是etime
始终以秒为单位显示经过的时间,而不是以天/小时为单位...
ps
来自debian squeeze的v3.2.8不支持该etimes
参数,但是来自debian wheezy的v3.3.3支持。
对于任何一天以上的事情,
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>
将为您提供更精确的答案。例如,这是进程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
ps
和stat
正显示出我的不同的结果。ps
表示该过程是1天前开始的,而stat显示是今天开始的。为什么?
TIME
列ps
未显示进程的实际运行时间。它显示了该进程的累计CPU时间-CPU对该进程进行工作的时间。
ps -eo pid,etime | grep $PID
通过这种方式,您可以获得十个最旧进程的列表:
ps -elf | 排序-r -k12 | 头-n 10
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”。
Perl的Proc :: ProcessTable可以解决这个问题:http : //search.cpan.org/dist/Proc-ProcessTable/
您可以使用以下命令在debian或ubuntu中安装它 sudo apt-get install libproc-processtable-perl
这里是单线:
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秒。
您可以bc
在mob的答案中使用这两个命令,并获得自过程开始以来经过的秒数:
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
如果将其放在路径上并这样称呼它:sincetime
它将打印进程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>
如果pattern是一个字符串或扩展的正则表达式,它将打印出与此模式匹配的所有进程以及它们启动后的秒数。:)
做一个ps -aef
。这将向您显示该过程开始的时间。然后使用date
命令查找当前时间。计算两者之间的差异,以找到流程的期限。
我做了与接受的答案类似的操作,但略有不同,因为我想根据进程名称和运行超过100秒的错误进程进行匹配
kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')
stat -t /proc/<pid> | awk '{print $14}'
以获取自该时间点以来的秒数的进程开始时间。与当前时间(date +%s
)比较,以获取该过程的当前时间。
stat -t /proc/<pid> | awk '{print $14}'
- date +%s
| BC”
如果有人需要用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;
}
来到某个地方..认为这是简单而有用的
您可以直接在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
killall -i --older-than 1h someprocessname