Как вы убиваете все процессы Linux, которые старше определенного возраста?


У меня проблема с некоторыми зомби-подобными процессами на определенном сервере, которые нужно время от времени убивать. Как я могу лучше всего определить те, которые работают дольше часа или около того?

14 65

14 ответов:

если их просто нужно убить:

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

Если вы хотите увидеть, что он соответствует

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

The -i флаг предложит вам с Да / нет для каждого процесса матча.

нашел ответ, который работает для меня:

внимание: это будет найти убить длительные процессы

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

(где user-id - это идентификатор конкретного пользователя с длительными процессами.)

второе регулярное выражение соответствует времени, которое имеет необязательную цифру дней, за которой следуют час, минута и второй компонент, и поэтому имеет длину не менее одного часа.

для всего, что старше одного дня,

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 запущен с 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 -elf | sort -r -k12 | head -n 10

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 секунд-разрешения на времени начала.

Джоди С и другие указали, что killall -i может быть использован, что нормально, если вы хотите использовать имя процесса, чтобы убить. Но если вы хотите убить по тем же параметрам, что и pgrep -f, вам нужно использовать что-то вроде следующего, используя pure 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".

можно использовать bc чтобы присоединиться к двум командам в ответе моба и получить, сколько секунд прошло с момента начала процесса:

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

edit:

от скуки в ожидании долгих процессов, чтобы запустить, это то, что вышло через несколько минут возиться:

#file: sincetime
#!/bin/bash
init=`stat -t /proc/ | awk '{print }'`
curr=`date +%s`
seconds=`echo $curr - $init| bc`
name=`cat /proc//cmdline`
echo $name $seconds

если вы поставите это на свой путь и назовете это так: с тех пор

он будет печатать процесс cmdline и секунд с момента запуска. Вы также можете поместить это в ваш путь:

#file: greptime
#!/bin/bash
pidlist=`ps ax | grep -i -E  | grep -v grep | awk '{print }' | grep -v PID | xargs echo`
for pid in $pidlist; do
    sincetime $pid
done

а чем если запустить:

greptime <pattern>

где patterns-это строка или расширенное регулярное выражение, он будет печатать все процессы, соответствующие этому шаблону и секундам с момента их запуска. :)

сделать ps -aef. это покажет вам время, в которое начался процесс. Затем с помощью найти текущее время. Вычислите разницу между ними, чтобы найти возраст процесса.

Я сделал что-то похожее на принятый ответ, но немного по-другому, так как я хочу соответствовать на основе имени процесса и на основе плохого процесса, работающего более 100 секунд

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

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

получить время запуска процесса в секундах с начала эпохи. Сравните с текущим временем (date +%s), чтобы получить текущий возраст процесса.

использование ps-это правильный путь. Я уже делал что-то подобное раньше, но у меня нет источника под рукой. Вообще-ps имеет возможность сказать ему, какие поля показывать и по которым сортировать. Вы можете сортировать вывод по времени выполнения, grep процесс, который вы хотите, а затем убить его.

HTH

если кому-то это нужно в 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);'

или, мы можем написать его как скрипт

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

и назовем его кронтаб вот так,

* * * * * longprockill.sh

моя версия sincetime выше @Rafael S. Calsaverini:

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

это отменяет выходные поля: во-первых, прошедшее время, полная команда, включая аргументы во-вторых. Это предпочтительно, поскольку полная команда может содержать пробелы.