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

StackOverflow https://stackoverflow.com/questions/6134

  •  08-06-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

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

Если вы хотите посмотреть, чему это соответствует

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

Тот Самый -i флажок подскажет вам "да" / "нет" для каждого совпадения процессов.

Другие советы

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

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

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

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

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

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

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

Джоди Си и другие отмечали , что 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's 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

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

он выведет командную строку процесса и секунды с момента запуска.Вы также можете поместить это в свой path:

#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 является строкой или расширенным регулярным выражением, он распечатает все процессы, соответствующие этому шаблону, и секунды с момента их запуска.:)

сделайте 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), чтобы получить текущий возраст процесса.

Использование 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);'

И назовите это crontab вот так,

* * * * * longprockill.sh

Моя версия sincetime выше автор : @Rafael S.Кальсаверини :

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top