Mic
Mic

Reputation: 38

How do I kill specific processes if their etime is greater than X amount of time?

I'm trying to take the output of a ps axo uname,pid,etime,time,cmd and kill all related processes with an etime>=10

I need to kill pids only for on specific users which are stored in a separate file, users.txt

Basically, I want to see all my columns and I want to find all php{5,54} processes that belong to specific users, stored in a file, and kill those processes if the execution time is over ten minutes. (kill -9 not needed)

Example ps output:

username   574        01:37 00:00:18 /ramdisk/bin/php54 /home/username/public_html/index.php
usernum2  1367        10:28 00:00:16 /ramdisk/bin/php54 /home/usernum2/public_html/index.php
user3     3971   1-04:17:31 00:00:14 /ramdisk/bin/php54 /home/user3/public_html/index.php
usernum4  9130     14:05:32 00:00:29 /ramdisk/bin/php54 /home/usernum4/public_html/index.php
username  9189   1-01:31:12 00:00:25 /ramdisk/bin/php54 /home/username/public_html/index.php

My thought has been to put the ps output into a file (say procs.txt), and then grep through that. EG:

ps axo uname,pid,etim,time,cmd | grep 'php5' | tee procs.txt

I could have two separate lines: one that says if column 3 is more than 5 characters kill the pid, which is easy, and then another with something like the following, but that doesn't leave me with the related pids, so I can't kill them:

for i in $( cat users.txt ); do grep $i procs.txt | awk '{print $3}' | awk -F: '{print $(NF-1)}' | awk '$1>=10{print $1}'; done

Upvotes: 1

Views: 1172

Answers (1)

jxh
jxh

Reputation: 70392

The following is a solution in bash.

To find all processes that match php5 or php54, for users in a file, I would use the U option to ps and egrep:

ps xo uname,pid,etim,time,cmd U"$(echo $(< users.txt))" | egrep '/php54? '

The U option will only display the processes that belong to the supplied list of users. The < is a shell builtin for cat, and the use of echo flattens the file entries into a single line that the ps command expects.

'/php54? ' indicates that the 4 is optional, and the space at the end makes sure it doesn't match (for example) php52. egrep uses regular expressions, so it allows the use of the ? meta character.

The output of this command can then be processed line by line with a while read:

ps xo uname,pid,etim,time,cmd U"$(echo $(< users.txt))" | egrep '/php54? ' \
| while read a
  do cols=($a)
     elapsed=${cols[2]}
     if [ ${#elapsed} -gt 5 ]
     then kill ${cols[1]}
     elif [ ${elapsed%%:*} -gt 9 ]
     then kill ${cols[1]}
     fi
  done

cols gets an array assignment, splitting the line a on whitespace boundaries. USER is in cols[0], PID in cols[1], and ELAPSED is in cols[2]. The PID is killed if the string length of ELAPSED is greater than 5 (indicating an elapsed time of at least an hour), or if the minutes field is greater than 9 (an elapsed time of at least 10 minutes). The %% expansion operator does a longest match suffix removal.

The solution can be compacted by read-ing directly into the relevant fields:

ps xo uname,pid,etim,time,cmd U"$(echo $(< users.txt))" | egrep '/php54? ' \
| while read user pid elapsed rest_of_line
  do if [ ${#elapsed} -gt 5 ]
     then kill $pid
     elif [ ${elapsed%%:*} -gt 9 ]
     then kill $pid
     fi
  done

Upvotes: 1

Related Questions