Во-первых, да, я видел этот вопрос:
Найти (и убить) старые процессы
Ответы там неверные и не работают. Я проголосовал и прокомментировал соответственно.
Процессы, которые я хочу убить, выглядят так, если они перечислены с 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, он либо выдает предупреждение, либо ничего не возвращает, если следовать совету указанного предупреждения.
GNU Killall может уничтожать процессы старше определенного возраста, используя их имя процесса.
if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h page.py;fi
find не всегда работает, не во всех системах есть доступные времена, и это может быть мой статус regex newb, но я не думаю, что вам нужно что-то большее, чем это:
ps -eo pid,etimes,comm,user,tty | awk '{if ($4 ~ /builder/ && $5 ~ /pts/ && $2>600) print $1}'
затем вы можете передать это, чтобы убить или что вам нужно.
Благодаря ответу Кристофера я смог адаптировать его к следующему:
find /proc -maxdepth 1 -user apache -type d -mmin +60 -exec basename {} \; \
| xargs ps | grep page.py | awk '{ print $1 }' | sudo xargs kill
-mmin
была команда поиска, которую мне не хватало.
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes | awk '{if ($2 >= 3600) print $2}'
Если хочешь, можешь накормить ps
со списком PID для поиска, например, e. грамм.:
ps h -O etimes 1 2 3
Я думаю, вы можете изменить некоторые из этих предыдущих ответов в соответствии со своими потребностями. А именно:
for FILE in (find . -maxdepth 1 -user processuser -type d -mmin +60) do kill -9 $(basename $FILE) # I can never get basename to work with find's exec. Let me know if you know how! done
Или
ps -eo pid,etime,comm | awk '$2!~/^..:..$/ && $3~/page\.py/ { print $1}' | kill -9
Я думаю, что второй может лучше всего соответствовать вашим потребностям. Версия find завершит уничтожение других процессов этим пользователем
- Кристофер Карел
apt-get install psmisc
killall -o 1h $proc_name
Преобразование etime
(прошедшее время) столбец ps
команду в секунды. Время указано в этом формате [[dd-]hh:]mm:ss
. Более новые версии ps
есть etimes
столбец, который выводит etime
значение в секундах.
Эта настраиваемая функция 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
(эквивалент переменной NF в 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}')
В 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
это должно работать
killall --older-than 1h $proc_name
Я изменил ответ, который они дали вам в предыдущем посте
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
.
Это, вероятно, перебор, но мне стало достаточно любопытно, чтобы закончить его и проверить, работает ли он (конечно, с другим именем процесса в моей системе). Вы можете убить захват $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";
}
}
У меня есть сервер с неправильными датами в / proc, и поиск не работает, поэтому я написал этот скрипт:
#!/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 "
Версия 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
Я использую этот простой скрипт, он принимает два аргумента: имя процесса и возраст в секундах.
#!/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
Другое решение меня не удовлетворило, большинство из них слишком загадочные (мои знания о 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
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
оно работает :)