2

I have written a script to determine the Load average on the server as follows:

#!/bin/bash

loadavg=`top -b -n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $2}'`

if [ "${loadavg}" -le  1 ]
then
echo "OK - Load Average = ${loadavg} | Load_Average=${loadavg}"
exit 0;
elif [ "${loadavg}" -gt 1 ] && [ "${loadavg}" -le 2 ]
then
echo "WARNING - Load Average = ${loadavg} | Load_Average=${loadavg}"
exit 1;
elif [ "${loadavg}" -gt 2 ]
then
echo "CRITICAL - Load Average = ${loadavg} | Load_Average=${loadavg}"
exit 2;
else
echo "UNKNOWN - Load Average = NaN | Load_Average=NaN"
fi

When the script is executed, it displays following error:

./loadavg.sh
./loadavg.sh: line 5: [:  0.06: integer expression expected
./loadavg.sh: line 9: [:  0.06: integer expression expected
./loadavg.sh: line 13: [:  0.06: integer expression expected
UNKNOWN - Load Average = NaN | Load_Average=NaN
  • 1
    top -b n1 | awk -F, '/load/ {print $4}' is a lot cleaner... – jasonwryan Jun 20 '14 at 9:41
  • 1
    How about loadavg=$( cut -d' ' -f1 </proc/loadavg ) - and no, still not an integer expression. It's a fixpoint. If you want to use -le and friends, consider cut -d' ' -f1 </proc/loadavg | cut -d. -f1, i.e. just drop everything after the integer part. – Felix Frank Jun 20 '14 at 9:59
  • Nagios alread has a check_load. Why are you making your own? – Stéphane Chazelas Jun 20 '14 at 10:23
  • 1
    Do the whole thing in awk. awk can do floating points, bash or [ cannot. – Stéphane Chazelas Jun 20 '14 at 10:24
  • You can get the load from uptime, not need to run one iteration of top for that. – Stéphane Chazelas Jun 20 '14 at 10:25
4

bash (contrary to ksh93 or zsh1) can't do floating point arithmetics. awk can though, so you can do the whole thing in awk.

Also, you don't need to use top (and wait 1 second) to get the load. The canonical way to get the load is from uptime.

uptime | awk '{load=+$(NF-2)}
  load > 2 {print "CRITICAL: " load; exit 2}
  load > 1 {print "WARNING: " load; exit 1}
  {print "OK: " load; exit 0}
  END {if (!NR) {print "UNKNOWN"; exit 3}'
exit

1 In zsh though, you need to use the (( loadavg > 2 )) instead of [ "$loadavg" -gt 2 ] syntax for comparing non-integers

  • On Linux, looking up /proc/loadavg will be more economic than shelling out to uptime, albeit less portable. – Felix Frank Jun 20 '14 at 13:54
2

top -b -n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $2}' returns nada, hence your errors.

  • top -b -n1 | grep -i load is displaying top - 15:02:31 up 2 days, 23:15, 1 user, load average: 0.37, 0.42, 0.38. – Mandar Shinde Jun 20 '14 at 9:36
  • @MandarShinde, that depends on the top implementation. That also depends on whether there are processes with load in their name or username. Though you're right that it's not the problem the OP is facing. – Stéphane Chazelas Jun 20 '14 at 14:09
2

Your loadavg is null, causes syntax errors by [:

$ top -b n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $2}'
<blank line here>

You must change it to:

$ top -b n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $1}'
 0.24

However, you should use newer test in your script, it can handle this problem:

$ [[ "" -gt 1 ]] || echo "OK"
OK

With older [:

$ [ "" -gt 1 ] || echo "OK"
bash: [: : integer expression expected
OK

Updated

bash can not handle floating point numbers, so your comparison (even with new test [[..]]) will show errors.

You can use another tools to do this task, like bc, awk...

Example:

$ [[ $(echo "3 > 1" | bc -l) == 1 ]] && echo OK
OK
$[[ $(echo "3 < 1" | bc -l) == 1 ]] || echo Not OK
Not OK
  • top -b -n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $2}' is printing 0.37 while top -b n1 | grep -i load | awk -F, '{print$4}'| awk -F: '{print $1}' prints load average. While the top -b -n1 | grep -i load output is top - 15:02:31 up 2 days, 23:15, 1 user, load average: 0.37, 0.42, 0.38. – Mandar Shinde Jun 20 '14 at 9:32
  • @MandarShinde: Yes, because you are parsing the output of top, it can produce different output. I tested in my Fedora machine. The main thing I want to show is you should using new test [[..]] instead of [..]. – cuonglm Jun 20 '14 at 9:36
  • When I replaced every [ with [[ and every ] with ]], it displayed the error: ./loadavg.sh: line 5: [[: 0.00: syntax error: invalid arithmetic operator (error token is ".00"). Tested on Red Hat Enterprise Linux Server release 6.5. – Mandar Shinde Jun 20 '14 at 9:39
  • @MandarShinde: bash can not understand float number, bash treat it as string, causing this error. – cuonglm Jun 20 '14 at 9:45
  • How should deal with this issue? – Mandar Shinde Jun 20 '14 at 9:47
0

First off, running top is more expensive than just grabbing "uptime".

$ uptime
 16:15:38 up 6 days, 23:22, 23 users,  load average: 0.99, 0.82, 0.70

Second, as @Stéphane Chazelas mentioned, bash doesn't like floating point arithmetic.

$ [[ "0.1" -lt 1 ]] 
bash: [[: 0.1: syntax error: invalid arithmetic operator (error token is ".1")

Fortunately, bash expansion can take care of that. From man bash:

   ${parameter%word}
   ${parameter%%word}
         Remove matching suffix pattern.  The word is expanded to produce a pattern just as in pathname expansion.   If
         the pattern matches a trailing portion of the expanded value of parameter, then the result of the expansion is
         the expanded value of parameter with the shortest matching pattern (the ``%'' case) or  the  longest  matching
         pattern  (the  ``%%'' case) deleted.  If parameter is @ or *, the pattern removal operation is applied to each
         positional parameter in turn, and the expansion is the resultant list.  If parameter is an array variable sub-
         scripted  with  @  or *, the pattern removal operation is applied to each member of the array in turn, and the
         expansion is the resultant list.

So it becomes pretty easy to strip out the decimal portions with "%.*"

$ la=`uptime | sed 's/.*average: \([0-9\.]*\).*/\1/'`
$ if [ ${la%.*} -lt 1 ]; then echo "OK - Load average is $la"; fi
OK - Load average is 0.42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.