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

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

8.08.2008 16:50:46
В Linux используетсяkillall -i --older-than 1h someprocessname
sanmai 10.12.2012 07:17:24
Или посмотрите мой ответ, который использует pgrepи, следовательно, является более гибким, чем killall.
g33kz0r 14.05.2013 15:57:25
14 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

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

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

31
9.05.2012 23:50:32
Хороший совет. Позже я наткнулся на ключ --older-than, но -i делает его полезным для проверки перед тем, как убить, кто что знает.
yukondude 11.05.2012 02:28:16
Какой смысл if [[ "$(uname)" = "Linux" ]];? Разве соответствующая часть не является просто killallкомандой? (Кажется, что окружающее ifпредложение можно было бы удалить, чтобы сделать этот ответ немного более прямым)
rinogo 23.04.2014 20:31:01
@ringo Потому что в некоторых системах (например, Solaris) killall - это совершенно другая команда. На Solaris он завершает все команды.
ctc 4.04.2016 14:51:30
Обратите внимание, что использование параметра killreall '--regex' приводит к игнорированию параметра --older-than. Радость!
Jeremy 29.05.2018 13:44:23

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

НТН

0
8.08.2008 16:54:49

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

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
22
9.08.2008 00:27:05
Кажется, что psи statпоказывает разные результаты для меня. psпоказывает, что процесс начался 1 день назад, а статистика показывает, что началась сегодня. Почему?
pl1nk 17.08.2012 15:31:57
Обратите внимание, что TIMEстолбец в psвыходных данных не показывает фактическое время выполнения процесса. Он показывает суммарное время ЦП процесса - время, в течение которого ЦП работали с процессом.
matthias krull 25.10.2012 10:04:57
спасибо, stat / proc / <pid> дал мне точный результат за время жизни процесса (время запуска)
baptx 14.11.2013 21:37:40
Попутно отмечу, что если процесс был начат в предыдущем году, в столбце СТАРТ указывается только год. Не очень большая точность. совсем. В дополнение к этому, когда я определял proc / id длительной сессии tmux с прошлого года, он сообщал дату этого года. Решение, которое я выбрал:ps -eo pid,etime | grep $PID
Steven Lu 16.01.2014 22:38:59

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

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

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

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

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

36
12.05.2013 00:54:23
Хм, ты убиваешь процесс? Я надеюсь, что люди понимают, что этот код не только находит, но и убивает, или они могут расстроиться.
Buttle Butkus 28.11.2012 21:11:25
@ButtleButkus Хороший вопрос. Да, вся причина вопроса заключалась в том, чтобы найти старые процессы и уничтожить их, но в явном виде не указано все это. Примечание для других: игнорируйте последний кусочек строки, если вам не нравятся гневные звонки от пользователей.
yukondude 29.11.2012 21:24:11
WTF! пожалуйста, измените название вопроса. к счастью, я не владею процессом!
neal aise 9.12.2012 23:04:10
Вы можете использовать опцию etimesвместо того, etimeчтобы всегда отображать прошедшее время в секундах, а не в днях / часах ...
Marki555 7.10.2014 09:52:32
@yukondude ты прав. Я только что проверил это, и psv3.2.8 из Debian Squeeze не поддерживает etimesпараметр, однако v3.3.3 из Debian Wheezy делает.
Marki555 22.10.2014 12:10:51

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

пс-эльф | сортировка -r -k12 | голова -n 10
9
8.08.2008 17:20:01
На самом деле это дает вам 10 последних процессов, потому что по умолчанию он показывает STIME - время запуска программы. Если бы он показывал ETIME - время, прошедшее с момента запуска программы, это было бы правильно.
Sarel Botha 16.12.2016 19:04:51

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

2
9.11.2011 18:31:39
К сожалению, вывод времени здесь сложно разобрать. Это может быть «ЧЧ: ММ» для краткосрочных процессов, или «MonDD» (возможно, локализованный!) Или даже год для очень длительных процессов.
Slaven Rezic 8.05.2015 10:11:01

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

7
13.08.2010 07:19:40

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

kill $(ps -o pid,bsdtime -p $(pgrep bad_process) | awk '{ if ($RN > 1 && $2 > 100) { print $1; }}')
1
11.08.2011 03:15:05
Разве $ RN не должен быть $ NR?
cmjohns 6.01.2020 13:56:52

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

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

1
16.02.2012 17:39:07
Мы можем объединить две команды, чтобы получить секунды с момента запуска процесса: «echo stat -t /proc/<pid> | awk '{print $14}'- date +%s| bc»
Rafael S. Calsaverini 14.06.2012 23:49:36
Это не всегда будет правильно - по крайней мере, для систем Linux 2.6. У меня есть процесс, который начался в 9:49, но stat -t (и stat) показывают, что он начался в 13:14.
user153275 10.01.2013 21:46:07
@dpk: иногда у вас есть основной процесс и работает несколько форков. Основной процесс должен быть 9:49, но дочерний процесс может иметь более позднее время. То же самое относится к потокам процесса.
higuita 8.01.2014 15:51:39

В случае, если кому-то это нужно в 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;
}
0
2.04.2012 09:07:24

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

Если вы поместите это на свой путь и назовете это так: 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>

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

3
15.06.2012 00:22:27

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

8
14.05.2013 15:54:11
Это то, что мне было нужно. Шесть лет спустя bash 5.0.3 жалуется на двойные скобки. Первые двойные скобки работают как одиночные, так же как и вторые без кавычек переменных. Тогда это сработало для меня. Спасибо.
Bill McGonigle 15.05.2019 16:41:11

Наткнулся где-то .. думал, это просто и полезно

Вы можете использовать команду в 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
0
6.07.2014 09:21:36

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

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

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

0
26.08.2018 04:29:40