Pergunta

I made a small script to kill PID's if they exceed expected cpu usage. It works, but there is a small problem.

Script:

while [ 1 ];
 do
  cpuUse=$(ps -eo %cpu | sort -nr | head -1)
  cpuMax=80
  PID=$(ps -eo %cpu,pid | sort -nr | head -1 | cut -c 6-20)

  if [ $cpuUse -gt $cpuMax ] ; then
   kill -9 "$PID"
   echo Killed PID $PID at the usage of $cpuUse out of $cpuMax

fi
exit 0
sleep 1;
done

It works if the integer is three digits long but fails if it drops to two and displays this:

./kill.sh: line 7: [: 51.3: integer expression expected

My question here is, how do I make bash understand the divider so it can kill processes under three digits.

Foi útil?

Solução

You are probably getting leading space in that variable. Try piping with tr to strip all spaces first:

cpuUse=$(ps -eo %cpu | sort -nr | head -1 | tr -d '[[:space:]]')

Remove text after dot from cpuUse variable:

cpuUse="${cpuUse%%.*}"

Also better to use quotes in if condition:

if [ "$cpuUse" -gt "$cpuMax" ] ; then

OR better use arithmetic operator (( and )):

if (( cpuUse > cpuMax ));  then

Outras dicas

As you see, bash doesn't grok non-integer numbers. You need to eliminate the decimal point and the following digits from $cpuUse before doing the comparison":

cpuUse=$(sed 's/\..*/' <<<$cpuUse)

However, this is really a job for awk. It will simplify much of what you're doing. Whenever you find yourself with greps of greps, or head and then cuts, you should be dealing with awk. Awk can easily combine these multiple piped seds, greps, cuts, heads, into a single command.

By the way, the correct ps command is:

 $ ps -eocpu="",pid=""

Using the ="" will eliminate the heading and simply give you the CPU and PID.

Looking at your program, there's no real need to sort. You're simply looking for all processes above that $cpuMax threshold:

ps -eo %cpu="",pid="" | awk '$1 > 80 {print $2}'

That prints out your PIDs which are over your threshold. Awk automatically loop through your entire input line-by-line. Awk also automatically divides each line into columns, and assigns each a variable from $1 and up. You can change the field divider with the -F parameter.

The above awk says look for all lines where the first column is above 80%, (the CPU usage) and print out the second column (the pid).

If you want some flexibility and be able to pass in different $cpuMax, you can use the -v parameter to set Awk variables:

ps -eo %cpu="",pid="" | awk -vcpuMax=$cpuMax '$1 > cpuMax {print $2}'

Now that you can pipe the output of this command into a while to delete all those processes:

pid=$(ps -eo %cpu="",pid="" | awk -vcpuMax=$cpuMax '$1 > cpuMax {print $2}')
if [[ -n $pid ]]
then
    kill -9 $pid
    echo "Killed the following processes:" $pid
fi
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top