First, yes I have seen this question:

http://serverfault.com/q/71360/14428

The answers there are incorrect and do not work. I have voted and commented accordingly.

The processes I want to kill look like this when listed with 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

I'm looking to setup a simple daily cron that will find and kill any page.py processes older than an hour.

The accepted answer on the aforementioned question does not work, as it doesn't match a range of times, it simply matches processes that have been running from 7 days to 7 days 23 hours 59 minutes and 59 seconds. I don't want to kill processes that have been running from 1-2 hours, but rather anything greater than 1 hour.

The other answer to the aforementioned question using find does not work, at least not on Gentoo or CentOS 5.4, it either spits out a warning, or returns nothing if the advice of said warning is followed.

link|improve this question

feedback

7 Answers

up vote 4 down vote accepted

Thanks to Christopher's answer I was able to adapt it to the following:

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

-mmin was the find command I was missing.

link|improve this answer
Not sure if -mmin is suitable for detecting the age of a process. – LatinSuD Sep 15 '10 at 18:19
It doesn't appear the /proc/ directories get modified a great deal, so this seems to work. That being said, I wouldn't want to claim it's impossible. – Christopher Karel Sep 15 '10 at 18:31
feedback

I think you can modify some of those previous answers to fit your needs. Namely:

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

Or

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

I think the second may best fit your needs. The find version would wind up nuking other processes by that user


--Christopher Karel

link|improve this answer
1  
Don't use kill -9 except as a last resort. Use -SIGINT or -SIGTERM. – Dennis Williamson Sep 15 '10 at 23:01
feedback

I modified the answer they gave you in previous post

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

The regular expression searches for 2 types of second argument:

  • Days in the form of digits and a minus sign.
  • Hours:minutes:seconds expression.

That should match everything except young processes who would have the form minutes:seconds.

link|improve this answer
Alternatively we could try do it the way PS does it. Substract the first argument of /proc/uptime from the 22nd argument of /proc/*/stat. – LatinSuD Sep 15 '10 at 18:44
feedback

This is probably overkill, but I got curious enough to finish it and test that it works (on a different process name on my system, of course). You can kill the capturing of $user and $pid to simplify the regexp, which I only added for debugging, and didn't feel like ripping back out. Named captures from perl 5.10 would shave off a couple more lines, but this should work on older perls.

You'll need to replace the print with a kill, of course, but I wasn't about to actually kill anything on my own system.

#!/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";                                                               
    }                                                                                 
}

link|improve this answer
feedback

I have a server with wrong dates in /proc and find doesn't work so I wrote this script:

#!/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 "
link|improve this answer
feedback

Python version using the ctime of the process entries in /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
link|improve this answer
feedback

The lstart field in ps gives a consistent time format which we can feed to date to convert to seconds since the epoch. Then we just compare that to the current time.

#!/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
link|improve this answer
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.