Bash script checking CPU usage by a specific process
First, I am new to this. I have experience with windows scripting and apple script, but not much with bash. What I am trying to do is grab the PID and% CPU of a particular process. then compare the% CPU with the set number, and if it is higher, kill the process. I feel like I'm close, but now I am getting the following error:
[[: 0.0: syntax error: invalid arithmetic operator (error token ".0")
what am I doing wrong? here's my code:
#!/bin/bash
declare -i app_pid
declare -i app_cpu
declare -i cpu_limit
app_name="top"
cpu_limit="50"
app_pid=`ps aux | grep $app_name | grep -v grep | awk {'print $2'}`
app_cpu=`ps aux | grep $app_name | grep -v grep | awk {'print $3'}`
if [[ ! $app_cpu -gt $cpu_limit ]]; then
echo "crap"
else
echo "we're good"
fi
Obviously I'm going to replace the echo in the if / then statement, but it acts like the statement is true no matter what the CPU load actually is (I tested this by changing -gt to -lt and it still echoes " shit"
Thanks for the help. Oh, and that's on OS X 10.7, in case that matters.
source to share
The problem is that bash cannot handle decimals. You can simply multiply them by 100 and work with equal integers instead:
#!/bin/bash
declare -i app_pid
declare -i app_cpu
declare -i cpu_limit
app_name="top"
cpu_limit="5000"
app_pid=`ps aux | grep $app_name | grep -v grep | awk {'print $2'}`
app_cpu=`ps aux | grep $app_name | grep -v grep | awk {'print $3*100'}`
if [[ $app_cpu -gt $cpu_limit ]]; then
echo "crap"
else
echo "we're good"
fi
Keep in mind that CPU percentage is not an optimal measure of an application's health. If you have two processes with infinite loops on the same base system, no other application with the same priority will ever exceed 33%, even if they are bypassed.
source to share
I came up with this using top and bc.
Use it by going to ex: ./script apache2 50 # max 50%
If there are many PIDs that match your program argument, only one will be calculated based on how they are listed. I could extend the script to catch them all and increase the percentage or something, but that would have to be done.
You can also pass in a number, ./script.sh 12345 50
which will force it to use the exact PID.
#!/bin/bash
# 1: ['command\ name' or PID number(,s)] 2: MAX_CPU_PERCENT
[[ $# -ne 2 ]] && exit 1
PID_NAMES=$1
# get all PIDS as nn,nn,nn
if [[ ! "$PID_NAMES" =~ ^[0-9,]+$ ]] ; then
PIDS=$(pgrep -d ',' -x $PID_NAMES)
else
PIDS=$PID_NAMES
fi
# echo "$PIDS $MAX_CPU"
MAX_CPU="$2"
MAX_CPU="$(echo "($MAX_CPU+0.5)/1" | bc)"
LOOP=1
while [[ $LOOP -eq 1 ]] ; do
sleep 0.3s
# Depending on your 'top' version and OS you might have
# to change head and tail line-numbers
LINE="$(top -b -d 0 -n 1 -p $PIDS | head -n 8 \
| tail -n 1 | sed -r 's/[ ]+/,/g' | \
sed -r 's/^\,|\,$//')"
# If multiple processes in $PIDS, $LINE will only match\
# the most active process
CURR_PID=$(echo "$LINE" | cut -d ',' -f 1)
# calculate cpu limits
CURR_CPU_FLOAT=$(echo "$LINE"| cut -d ',' -f 9)
CURR_CPU=$(echo "($CURR_CPU_FLOAT+0.5)/1" | bc)
echo "PID $CURR_PID: $CURR_CPU""%"
if [[ $CURR_CPU -ge $MAX_CPU ]] ; then
echo "PID $CURR_PID ($PID_NAMES) went over $MAX_CPU""%"
echo "[[ $CURR_CPU""% -ge $MAX_CPU""% ]]"
LOOP=0
break
fi
done
echo "Stopped"
source to share
Eric, I used a modified version of your code to create a new script that does something like this. I hope you don't mind.
A bash script to get the CPU usage by process Usage:
nohup ./check_proc bwengine 70 &
bwegnine
- this is the name of the process we want to monitor 70 - this is only logged when the process is using more than 70% of the CPU.
Check the logs: /var/log/check_procs.log
The output should look like this:
DATE | TOTAL CPU | CPU USAGE | Process details
Example:
03/12/14 17:11 |20.99|98| ProdPROXY-ProdProxyPA.tra
03/12/14 17:11 |20.99|100| ProdPROXY-ProdProxyPA.tra
Full blog link: http://felipeferreira.net/?p=1453
source to share
It is also useful to have app_user
information available to check if the current user has permission to kill / modify the current process. This information can be obtained along with the necessary app_pid
and app_cpu
with the help read
, eliminating the need for awk
or any other parser parser:
read app_user app_pid tmp_cpu stuff <<< \
$( ps aux | grep "$app_name" | grep -v "grep\|defunct\|${0##*/}" )
Then you can get app_cpu * 100
with
app_cpu=$((${tmp_cpu%.*} * 100))
Note. Inclusion defunct
and ${0##*/}
in grep -v
prevents multiple processes matching $app_name
.
source to share