0

I'm trying to build a script to trigger an action/alert for a linux appliance when load average reaches a specific threshold.

Script looks like this:

!/bin/bash

load=`echo $(cat /proc/loadavg | awk '{print $2}')`
if [ "$load" -gt 5 ]; then
        echo "foo alert!"
fi

echo "System Load $(cat /proc/loadavg)"

Credit to helloacm.com for getting me started here.

When I run it, I get an error:

./foocheck.sh: line 4: [: 0.03: integer expression expected

Which makes sense -- it's seeing the period/decimal and thinking that I'm comparing a string to an integer.

Most solutions I've found for this involve bc -l which isn't available on this appliance. I need to find a way to compare these values without using bc. Any ideas?

7 Answers 7

2

You can only use integer part to compare:

load=$(awk '{print $2}' /proc/loadavg | cut -d. -f1)
2

Since you have awk available and awk could process floating point values, do:

awk '($1>5){print("yes")}'

Edited script:

#!/bin/bash

load=`echo $(cat /proc/loadavg | awk '{print $2}')`
loadtest=$(echo "$load" | awk '($1>5){print("yes")}')
if [ "$loadtest" = yes ]; then
    echo "foo alert!"
fi

of course, the whole script could be further simplified using only awk.

Maybe:

#!/bin/bash
awk '($2>5){print("foo alert!")}' /proc/loadavg
1
set -- $(cat /proc/loadavg)
load=${2/./}
if [ "$load" -ge 500 ]; then
  echo alert
fi

Get the load average from /proc, and set the positional parameters based on those fields. Grab the 2nd field and strip out the period. If that (now numeric) value is greater than or equal to 500, alert. This assumes (the current) behavior where the load averages are presented to two decimal points. Thanks to Arrow for pointing out a better way.

2
  • This is similar to what I ended up doing, although I used if [ "${load%.*}" -ge "$loadthreshold" ]; and let bash just lop off the rest. Full example in answer field below.
    – Mike B
    Commented Jun 23, 2017 at 19:20
  • 1
    That will stop working the day Linux decides to have 3 digits after the period in there. Commented Jun 23, 2017 at 19:32
1

Short answer: you can't do that. Actually, bash can't do that, though you the human could do it just fine. See https://stackoverflow.com/questions/11541568/how-to-do-float-comparison-in-bash for more detail.

1

bash cannot do floating points. Use zsh, ksh93 or yash instead:

#! /bin/zsh -
read ignore load ignore < /proc/loadavg || exit
if ((load > 5)); then
  echo >&2 Alert
fi

Or since you're using awk already (along a few unnecessary commands):

#! /bin/sh -
awk '$2 > 5 {print "Alert"}' < /proc/loadavg >&2

Or if you need it in a sh if construct:

#! /bin/sh -
if awk '{exit !($2 > 5)}' < /proc/loadavg; then
  echo >&2 Alert
fi
0

Convert to integer and an array might be the shortest way:

!/bin/bash
# Remove decimal point (multiply by 100) and put it into an array
declare -a load=( $(tr -d . < /proc/loadavg) )
if [ ${load[0]} -gt 500 ]; then
    echo "foo alert!"
fi
echo "System Load $(cat /proc/loadavg)"
1
  • 2
    Should be load[1] (the second value or the 5 minute average) in any case.
    – user232326
    Commented Jun 19, 2017 at 21:37
0

I still give credit to @jeff-schaller but for completeness, here was the approach I went with:

#!/bin/bash

#Threshold value for minimum load average necessary to trigger an alert. 
loadthreshold=30

#Admin defined value for where to send email alert
[email protected]

#Time/date for filename saving later.
logtimestamp=`date +%Y-%m-%d.%H-%M-%S`

#Check the load average value for the past 5-minute time span.
load=`echo $(cat /proc/loadavg | awk '{print $2}')`

#Truncate the load average value (leaving off the fractional values) and trigger an alert action if it's greater than (or equal to) the admin-defined threshold.
if [ "${load%.*}" -ge "$loadthreshold" ]; then
    echo "Yo admin, your system load average is pretty high: $load.  Check the server  " | mail -s "System load average spike detected" "$alertrecipient"
    tar cvzf "high-la-logs$logtimestamp.tar.gz" /var/log/ 
fi

The only real difference is leveraging "${load%.*}" to lop off the stuff to the right of the decimal.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .