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 
6
  • 1
    top -b n1 | awk -F, '/load/ {print $4}' is a lot cleaner...CommentedJun 20, 2014 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.CommentedJun 20, 2014 at 9:59
  • Nagios alread has a check_load. Why are you making your own?CommentedJun 20, 2014 at 10:23
  • 1
    Do the whole thing in awk. awk can do floating points, bash or [ cannot.CommentedJun 20, 2014 at 10:24
  • You can get the load from uptime, not need to run one iteration of top for that.CommentedJun 20, 2014 at 10:25

4 Answers 4

5

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

1
  • On Linux, looking up /proc/loadavg will be more economic than shelling out to uptime, albeit less portable.CommentedJun 20, 2014 at 13:54
2

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

2
  • 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.CommentedJun 20, 2014 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.CommentedJun 20, 2014 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 
7
  • 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.CommentedJun 20, 2014 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
    CommentedJun 20, 2014 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.CommentedJun 20, 2014 at 9:39
  • @MandarShinde: bash can not understand float number, bash treat it as string, causing this error.
    – cuonglm
    CommentedJun 20, 2014 at 9:45
  • How should deal with this issue?CommentedJun 20, 2014 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 

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.