Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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
share|improve this question
    
I guess this belongs to Stackoverflow, a Q&A site dedicated to programming. –  psimon Jun 20 at 9:29
1  
top -b n1 | awk -F, '/load/ {print $4}' is a lot cleaner... –  jasonwryan Jun 20 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 at 9:59
1  
@psimon shell scripting questions are on topic and welcome here. Please familiarize yourself with the site's scope before making such suggestions. –  terdon Jun 20 at 10:06
1  
Do the whole thing in awk. awk can do floating points, bash or [ cannot. –  Stéphane Chazelas Jun 20 at 10:24
show 4 more comments

4 Answers

up vote 4 down vote accepted

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

share|improve this answer
    
On Linux, looking up /proc/loadavg will be more economic than shelling out to uptime, albeit less portable. –  Felix Frank Jun 20 at 13:54
add comment

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
share|improve this answer
add comment

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
share|improve this answer
    
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 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 [..]. –  Gnouc Jun 20 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 at 9:39
    
@MandarShinde: bash can not understand float number, bash treat it as string, causing this error. –  Gnouc Jun 20 at 9:45
    
How should deal with this issue? –  Mandar Shinde Jun 20 at 9:47
show 2 more comments

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

share|improve this answer
    
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 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 at 14:09
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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