Как убить процессы старше «т»?


14

Во-первых, да, я видел этот вопрос:

Найти (и убить) старые процессы

Ответы там неверны и не работают. Я проголосовал и прокомментировал соответственно.

Процессы, которые я хочу убить, выглядят так, когда перечислены с ps aux | grep page.py:

apache 424 0,0 0,1 6996 4564? S 07:02 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 2686 0,0 0,1 7000 3460? S Sep10 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 2926 0,0 0,0 6996 1404? S Sep02 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 7398 0,0 0,0 6996 1400? S Sep01 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 9423 0,0 0,1 6996 3824? S Sep10 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 11022 0,0 0,0 7004 1400? S Sep01 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15343 0,0 0,1 7004 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15364 0,0 0,1 7004 3792? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 15397 0,0 0,1 6996 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 16817 0,0 0,1 7000 3788? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 17590 0,0 0,0 7000 1432? S Sep07 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 24448 0,0 0,0 7000 1432? S Sep07 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py
apache 30361 0,0 0,1 6996 3776? S Sep09 0:00 /usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py

Я ищу, чтобы установить простой ежедневный cron, который будет находить и убивать любые page.pyпроцессы старше часа.

Принятый ответ на вышеупомянутый вопрос не работает, так как он не соответствует диапазону времени, он просто соответствует процессам, которые выполнялись от 7 дней до 7 дней 23 часа 59 минут и 59 секунд. Я не хочу убивать процессы, которые выполнялись от 1 до 2 часов, а лучше от 1 часа.

Другой ответ на вышеупомянутый вопрос с использованием findне работает, по крайней мере, в Gentoo или CentOS 5.4, он либо выдает предупреждение, либо ничего не возвращает, если следовать совету упомянутого предупреждения.

Ответы:


22

GNU Killall может уничтожать процессы старше указанного возраста, используя их имена.

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

1
Эта опция недоступна в CentOS 6.6. Версия: killall (PSmisc) 22.6.
безымянный

9

Благодаря ответу Кристофера я смог адаптировать его к следующему:

find /proc -maxdepth 1 -user apache -type d -mmin +60 -exec basename {} \; \
| xargs ps | grep page.py | awk '{ print $1 }' | sudo xargs kill

-mmin была команда поиска, которую я пропустил.


3
Не уверен, что -mmin подходит для определения возраста процесса.
LatinSuD

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

Я не думаю, что это отвечает на ваш вопрос, так как этот ответ слишком узок, а вопрос шире.
Пой

И я бы сказал, что даже больше - он вообще не работает: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls- / sbin / init не указан в списке, несмотря на то, что время безотказной работы исчисляется днями, а не часами. Кажется, вы не можете полагаться на время модификации / proc /.
Пой

3
К сожалению, временные метки в / proc не могут зависеть от этого. По крайней мере, больше.
дпк

8

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

ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
  • перечислить все процессы и предоставить столбцы PID, ELAPSED (etimes = секунд), COMMAND, USER, TT (спасибо @ahoffman)
  • с помощью awk выведите PID, где 4-й столбец ($ 4, USER) содержит текст 'builder', а 5-й столбец ($ 5, TT) содержит текст 'pts', а столбец ELAPSED имеет значение больше 600 секунд (спасибо @amtd)

затем вы можете передать это, чтобы убить или что-то еще, что вам нужно.


Я думаю, что это одно из наиболее надежных решений, особенно с точки зрения использования вами ps, но я бы сложил кратные greps в единое целое awk, и для безопасности ограничиваю совпадения шаблонов для определенных столбцов (исключая, например, сопоставление имени команды строитель и т. д.)
JMTD

Это хорошо, если ваш временной диапазон указан в днях, но не будет работать, если вы хотите проверить истекшее время в часах, минутах или секундах.
Vlastimil Ovčáčík

используйте «etimes» вместо «etime», это вернет истекшее время в секундах, которое намного легче проанализировать.
ахофманн

@jmtd & ahofmann: я обновил в соответствии с вашим комментарием. Я надеюсь, что это так, как вы и хотели
eugenevd

5
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

Если вы хотите, вы можете добавить psсписок PID для поиска, например:

ps h -O etimes 1 2 3

2
etimesработает только для новичковps
Тино

4

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

для ФАЙЛА в (найти. -maxdepth 1 -пользователь-обработчик -тип d -mmin +60)
  do kill -9 $ (basename $ FILE) # Я никогда не смогу заставить basename работать с exec для find. Дайте мне знать, если знаете как!
сделано

Или

ps -eo pid, etime, comm | awk '$ 2! ~ /^..:..$/ && $ 3 ~ / page \ .py / {print $ 1}' | убить -9

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


Кристофер Карел


7
Не используйте, kill -9кроме как в крайнем случае. Используйте -SIGINTили -SIGTERM.
Приостановлено до дальнейшего уведомления.

При этом в качестве критерия тестирования используется формат прошедшего времени, а не его значение. psбудет выводить время в ^..:..$формате, когда оно меньше часа.
Властимил Овчачик

4
apt-get install psmisc

killall -o 1h $proc_name

Не могли бы вы помочь объяснить больше об psmiscутилите? ОП упомянул CentOS; это доступно как RPM?
Касталья

4

Проблема

Преобразование etime(истекшее время) столбца psкоманды в секунды. Указание времени в этом формате [[dd-]hh:]mm:ss. Более новые версии psимеют etimesстолбец, который выводит etimeзначение в секундах.

Решение: простая пользовательская функция awk

Эта пользовательская функция awk поддерживает все форматы etimeстолбцов (например 03-12:30:59, 00:07и т. Д.). Просто вставьте его в свой скрипт на awk, это решение для одной строки.

function sec(T){C=split(T,A,"[:-]"); return A[C>3?C-3:99]*86400 + A[C>2?C-2:99]*3600 + A[C>1?C-1:99]*60 + A[C>0?C-0:99]*1}
  • sec(T) преобразует T в секунды
  • Tуказание времени в [[dd-]hh:]mm:ssформате (например etime)
  • Cколичество полей в T(эквивалентно переменной NK в awk)
  • Aмассив полей в T(эквивалентно переменной $ awk)
  • A[C>3?C-3:99]Это безопасный способ ссылаться на четвертое значение (т.е. количество дней) в обратном порядке. Этот подход полезен, потому что дни и часы не являются обязательными. Если массив не достаточно длинный, это разыменование, A[99]которое даст 0значение. Я предполагаю, 99что достаточно высок для большинства случаев использования.
  • возвращает секунды как целое число

Пример из реального мира

Этот bash oneliner убьет soffice.binпроцесс, запущенный под текущим пользователем, если процесс старше 180 секунд.

kill -9 $(ps cx -o command,etime,pid | awk '/^soffice.bin/ {if (sec($2)>180) {print $3}} function sec(T){C=split(T,A,"[:-]"); return A[C>3?C-3:99]*86400 + A[C>2?C-2:99]*3600 + A[C>1?C-1:99]*60 + A[C>0?C-0:99]*1}')

1
Гораздо лучше, чем другие ответы. он также обрабатывает несколько процедур.
Денни Вайнберг

Было бы лучше поместить 'command' или 'args' в конец списка форматов 'ps', чтобы можно было выполнить поиск по всей строке command / args. Размещение его в начале приведет к обрезанию ps более длинных команд.
Максим

1

lstartПоле psдает последовательный формат времени , который мы можем подать в dateпреобразовать в секундах с начала эпохи. Тогда мы просто сравним это с текущим временем.

#!/bin/bash
current_time=$(date +%s)
ps axo lstart=,pid=,cmd= |
    grep page.py |
    while read line
    do
        # 60 * 60 is one hour, multiply additional or different factors for other thresholds 
        if (( $(date -d "${line:0:25}" +%s) < current_time - 60 * 60 ))
        then
            echo $line | cut -d ' ' -f 6    # change echo to kill
        fi
    done

0

Я изменил ответ, который они дали вам в предыдущем посте

ps -eo pid,etime,comm | 
egrep '^ *[0-9]+ +([0-9]+-[^ ]*|[0-9]{2}:[0-9]{2}:[0-9]{2}) +/usr/bin/python2.6 /u/apps/pysnpp/current/bin/page.py' | 
awk '{print $1}' | 
xargs kill

Регулярное выражение ищет 2 типа второго аргумента:

  • Дни в виде цифр и знака минус.
  • Hours:minutes:seconds выражение.

Это должно соответствовать всем, кроме молодых процессов, которые будут иметь форму minutes:seconds.


В качестве альтернативы мы можем попытаться сделать это так, как это делает PS. Вычтите первый аргумент / proc / uptime из 22-го аргумента / proc / * / stat.
LatinSuD

0

Это, вероятно, излишне, но мне стало любопытно закончить его и проверить, работает ли он (конечно, с другим именем процесса в моей системе). Вы можете убить захват $userи$pid упростить регулярное выражение, которое я добавил только для отладки, и которое не вырвалось обратно. Именованные захваты из Perl 5.10 сбрили бы еще пару строк, но это должно работать на старых Perl.

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

#!/usr/bin/perl -T
use strict; use warnings;

$ENV{"PATH"} = "/usr/bin:/bin";                                                       

my (undef,undef,$hour) = localtime(time);                                             
my $target = $hour - 2; # Flag process before this hour                               
my $grep = 'page.py';                                                   

my @proclist = `ps -ef | grep $grep`;                                                 
foreach my $proc (@proclist)                                                          
{                                                                                     
    $proc =~ /(\w+)\s+(\d+)\s+\d+\s+\d+\s+(.*?).*/;                   
    my $user = $1;                                                                    
    my $pid = $2;                                                                     
    my $stime = $3;                                                                   

    $stime =~ s/(\d+):(\d+)/$1/;                                                      

    # We're going to do a numeric compare against strings that                        
    # potentially compare things like 'Aug01' when the STIME is old                   
    # enough.  We don't care, and we want to catch those old pids, so                 
    # we just turn the warnings off inside this foreach.                              
    no warnings 'numeric';                                                            

    unless ($stime > $target)                                                         
    {                                                                                 
        print "$pid\n";                                                               
    }                                                                                 
}


0

У меня есть сервер с неправильными датами в / proc и find не работает, поэтому я написал этот скрипт:

#!/bin/bash

MAX_DAYS=7  #set the max days you want here
MAX_TIME=$(( $(date +'%s') - $((60*60*24*$MAX_DAYS)) ))

function search_and_destroy()
{
        PATTERN=$1
        for p in $(ps ux|grep "$PATTERN"|grep -v grep| awk '{ print $2 }')
        do
            test $(( $MAX_TIME - $(date -d "`ps -p $p -o lstart=`" +'%s') )) -ge 0 && kill -9 $p
        done
}

search_and_destroy " command1 "
search_and_destroy " command2 "

0

Версия Python, использующая ctime записей процесса в /proc:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kills processes older than HOURS_DELTA hours

import os, time

SIGNAL=15
HOURS_DELTA=1

pids = [int(pid) for pid in os.listdir('/proc') if pid.isdigit()]

for pid in pids:
    if os.stat(os.path.join('/proc', str(pid))).st_ctime < time.time() - HOURS_DELTA * 3600:
        try:
            os.kill(pid, SIGNAL)
        except:
            print "Couldn't kill process %d" % pid

0

Я использую этот простой скрипт, он принимает два аргумента имя процесса и возраст в секундах.

#!/bin/bash
# first argument name of the process to check
# second argument maximum age in seconds
# i.e kill lighttpd after 5 minutes
#   script.sh lighttpd 300 
process=$1
maximum_runtime=$2
pid=`pgrep $process`
if [ $? -ne 0 ]
then
        exit 0
fi
process_start_time=`stat /proc/$pid/cmdline --printf '%X'`
current_time=`date +%s`
let diff=$current_time-$process_start_time

if [ $diff -gt $maximum_runtime ]
then
        kill -3 $pid
fi

0

это должно работать

killall --older-than 1h $proc_name


1
Как это добавляет или улучшает [уже существующие ответы]?
Reaces

2
@Reaces: Честно говоря, мне пришлось искать упоминание одного ответа, --older-than и его легко не заметить. По сравнению с другими ответами это намного проще, и теперь оно доступно и на EL7.
Свен

@ Повторяет, что это просто делает проще, чем написание скриптов с использованием awk / sed и т. Д., Чтобы убить процесс, это, я полагаю, намного проще и чище
Джабир Ахмед

0

Меня не устраивало другое решение, большинство из них слишком загадочные (мои знания bash ограничены), и поэтому я не могу их настроить ...
Я создал собственное решение, оно, вероятно, не самое лучшее, но оно работает и это читабельно

Вы можете сохранить этот скрипт в файле и сделать его исполняемым (в конце концов, вызовите его с помощью cron)

#!/bin/bash
## time in second that trigger the kill
LIMIT=10
## [] skip the grep from the process list
PROC_NAME="[m]y process name"
## etimes return the time in seconds
TIME_SEC=$(ps axo etimes,pid,command | grep "$PROC_NAME" | awk {'print$1'})
PID=$(ps axo etimes,pid,command | grep "$PROC_NAME" | awk {'print$2'})

if [ -n "$TIME_SEC" ] 
    then
    if (( $TIME_SEC > $LIMIT )); then
        kill $PID
    fi
fi

-2

72 = 3 дня 48 = 2 дня 24 = 1 день

a1=$(TZ=72 date +%d) ps -ef| cat filex.txt | sed '/[JFMASOND][aepuco][nbrylgptvc] '$a1'/!d' | awk '{ print $2 " " $5 " " $6 }' > file2.txt

оно работает :)


1
Это вполне может быть, но довольно сложно читать и учиться. Подумайте о переформатировании с некоторыми новыми строками и прочим ... сценарии лучше, чем однострочные для обучения.
Сокол Момот
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.