Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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.

share|improve this question
add comment

11 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.

share|improve this answer
1  
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
    
I don't think this answers your question since this answer is too narrow and question is wider. –  poige May 29 '12 at 5:23
    
And I'd say even more — it doesn't work at all: find /proc -maxdepth 1 -type d -name 1 -mmin +60 -ls — /sbin/init isn't being listed in despite uptime counts for days, not hours. It seems you can't rely on /proc/'s dirs modification time. –  poige May 29 '12 at 5:53
    
The timestamps in /proc can't be depended on for this, unfortunately. At least not any more. –  dpk Jan 10 '13 at 21:46
add comment

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

share|improve this answer
3  
Don't use kill -9 except as a last resort. Use -SIGINT or -SIGTERM. –  Dennis Williamson Sep 15 '10 at 23:01
add comment
# get elapsed time in seconds, filter our only those who >= 3600 sec
ps axh -O etimes  | awk '{if ($2 >= 3600) print $2}'

If you wan't you can feed ps with list of PIDs to lookup within, for e. g.:

ps h -O etimes 1 2 3
share|improve this answer
add comment

find doesnt always work, not every system has etimes available, and it might be my regex newb status, but I dont think you need anything more than this:

ps -eo pid,etime,comm,user,tty | grep builder | grep pts | grep -v bash |awk '$2~/-/ {if ($2>7) print $1}'
  • find process running as user builder, executed from interactive login pts, exclude bash processes
  • the second column will be the elapsed time (etime)
  • use awk on the 2nd column ($2) and get with a regex (~) the string before the -(ps etime prints in format dd-hh:mm:ss)
  • If that value is larger than 7 (ie, been running more than seven days) print what is in the first column $1 , ie pid

you can then pipe that to kill or whatever your need may be.

share|improve this answer
    
I think this is one of the more robust solutions, especially in terms of your use of ps, but I'd fold the multiple greps into the single awk, and for safety restrict the pattern matches to particular columns (to rule out e.g. a command name matching builder, etc.) –  jmtd Feb 6 '13 at 16:08
add comment

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.

share|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
add comment

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";                                                               
    }                                                                                 
}

share|improve this answer
add comment

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 "
share|improve this answer
add comment

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
share|improve this answer
add comment

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
share|improve this answer
add comment

GNU Killall can kill processes older than a given age, using their processname.

if [[ "$(uname)" = "Linux" ]];then killall --older-than 1h page.py;fi
share|improve this answer
add comment

I use this simple script it takes two arguments name of process and age in seconds.

#!/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
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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