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

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

Ответы [ 14 ]

36 голосов
/ 08 августа 2008

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

предупреждение: это найдет и убьет долго выполняющиеся процессы

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

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

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

30 голосов
/ 10 мая 2012

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

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

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

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

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

22 голосов
/ 08 августа 2008

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

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, которая отображается только как июнь 22:

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
9 голосов
/ 08 августа 2008

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

ps -elf | sort -r -k12 | head -n 10
8 голосов
/ 14 мая 2013

Джоди Си и другие отметили, что можно использовать 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".

7 голосов
/ 13 августа 2010

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 секунду во время запуска.

3 голосов
/ 15 июня 2012

Вы можете использовать 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

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

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

#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>

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

2 голосов
/ 24 октября 2009

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

1 голос
/ 16 февраля 2012

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

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

1 голос
/ 11 августа 2011

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

kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...