I have the following script that basically looks for a certain process name and tracks if its elapsed for more than X time, to kill it.
#!/bin/bash
PROC_NAME=my_proc_name
# Get all PIDs for process name
procs=(`ps aux | grep $PROC_NAME | awk '{print $2}'`)
# for each PID in PIDs array
for pid in $procs; do
# get elapsed time in form mm:ss and remove ":" character
# to make it easier to parse time
time=(`ps -o etime $pid | sed -e 's/[:-]/ /g'`)
# get minutes from time
min=${time[1]}
# if proces runs 5 hours then kill it
if [ "$min" -gt "300" ]; then
kill -9 $pid
fi
done;
This version of the script kills the process if the elapsed time exceeds 5 mins. But what if i want to account for an elapsed time of 5 hours instead?
I thought itd be as simple as adjusting 5 mins to 300 mins (60 mins x 5 = 300mins = 5 hours) but i realized that the format is hours:min:secs .. so will need to make sure sed gets the hours, right? if so, how do i do that?
CodePudding user response:
You can use bash regular expression to get different components :
#!/bin/bash
PROC_NAME=my_proc_name
# Get all PIDs for process name
procs=(`ps aux | grep $PROC_NAME | awk '{print $2}'`)
pattern='((.*)-)?((..):)?(..):(..)'
for pid in ${procs[@]}; do
if [[ "$(ps -o etime= -p $pid)" =~ $pattern ]] && {
[ -n "${BASH_REMATCH[2]}" ] || # if day component exists, then it's more than 5 hours
{ [ -n "${BASH_REMATCH[4]}" ] && ((10#${BASH_REMATCH[4]} >= 5)); } }; then
echo kill -9 $pid
fi
done
Remove echo
(dry run) if you see the result is expected.
Explanation of pattern='((.*)-)?((..):)?(..):(..)' :
1) ((.*)-)? means optional day component
if present like 9- then ${BASH_REMATCH[1]} = 9-, ${BASH_REMATCH[2]} = 9
if absent, ${BASH_REMATCH[2]} is empty
2) ((..):)? means optional hour component
if present like 05 then ${BASH_REMATCH[3]} = 05:,${BASH_REMATCH[4]} = 05
if absent, ${BASH_REMATCH[4]} is empty
CodePudding user response:
Usually, on many systems, I transform the ps
elapsed time in seconds with awk
:
#! /bin/bash
...
declare -i E_TIME=$(ps \
-p ${THE_PID} \
-o etime= \
| awk '
{
gsub(/^ /, "")
gsub(/ $/, "")
}
/^[0-9]*-/ {
days = $0
gsub(/-.*$/, "", days)
gsub(/^0 /, "", days)
if (days == "") days = "0"
gsub(/^[0-9] -/, "", $0)
}
/^[0-9] :[0-9] :[0-9] $/ {
hours = $0
gsub(/:.*$/, "", hours)
gsub(/^0 /, "", hours)
if (hours == "") hours = "0"
gsub(/^[0-9] :/, "", $0)
}
/^[0-9] :[0-9] $/ {
minutes = $0
gsub(/:.*$/, "", minutes)
gsub(/^0 /, "", minutes)
if (minutes == "") minutes = "0"
gsub(/^[0-9] :/, "", $0)
}
/^[0-9] $/ {
seconds = $0
gsub(/:.*$/, "", seconds)
gsub(/^0 /, "", seconds)
if (seconds == "") seconds = "0"
}
{
print seconds 60 * (minutes 60 * (hours 24 * days) )
}
'
)
echo "E_TIME=${E_TIME}"