15

I'm having a rather weird issue, I'm running a script (Bash) on multiple servers and it stopped working on one of the servers (works perfectly fine on all other servers).

Here is the problem part of the script: (I did not write it myself, all credits go to "Rich") (http://www.notrainers.org/monitoring-memory-usage-on-linux-with-nagios-and-nrpe/)

 if [ "$result" -lt "$warn_level" ]; then #Line 56 echo "Memory OK. $result% used." exit 0; elif [ "$result" -ge "$warn_level" ] && [ "$result" -le "$critical_level" ]; then #Line 59 echo "Memory WARNING. $result% used." exit 1; elif [ "$result" -gt "$critical_level" ]; then #Line 62 echo "Memory CRITICAL. $result% used." exit 2; fi 

Complete error message:

./check_memory.sh: Line 56: [: 7.: integer expression expected ./check_memory.sh: Line 59: [: 7.: integer expression expected ./check_memory.sh: Line 62: [: 7.: integer expression expected 

If you need more info, let me know and I will try to supply it as fast as possible.

Appreciate all inputs :)

    3 Answers 3

    6

    By the look of things, your result variable has a . in it after the number making bash not recognise it as such. You can reproduce the error by simply doing:

    [ 7. -gt 1 ] 

    If you add more of the script to your question, |I can suggest where this might be coming from.

    Update

    Looking at the full script, I would just replace the line:

    result=$(echo "$used / $total * 100" |bc -l|cut -c -2) 

    With:

    result=$(( 100 * used / total )) 

    Since used and total are integers and bash does integer arithmetic, though note the shifting of the multiplication be 100 to the beginning. Or if you want to ensure correct rounding ('integer division' in computing always effectively rounds down):

    result=$( printf '%.0f' $(echo "$used / $total * 100" | bc -l) ) 

    This will ensure that there are no trailing dots in result. The approach using cut is not a very good idea since it is only valid for result in the range 10-99. It will fail for a result from 0-9 (as in your case) and also numbers above 99.

    Update 2

    From @Stephane's comment below, you are better to round down when comparing to thresholds. Considering this, there is another small error with the snippet in the question - notice the inconsistency between the comparisons used for the warn_level and the critical_level. The comparisons for warn_level are correct, but critical_level uses -le (lesser or equal) instead of -lt (just lesser). Consider when result is slightly larger than critical_level - it will be rounded down to critical_level and not trigger the critical warning even though it should (and would if a -lt comparison was used).

    Perhaps not much of an issue, but here is the corrected code:

    if [ "$result" -lt "$warn_level" ]; then echo "Memory OK. $result% used." exit 0; elif [ "$result" -lt "$critical_level" ]; then echo "Memory WARNING. $result% used." exit 1; else echo "Memory CRITICAL. $result% used." exit 2; fi 

    The -ge tests are also redundant since these cases are implied on reaching the elif/else, so have been removed.

    1
    • 2
      However, to check against thresholds, you don't want to round up. 49.6 should still be OK if the warning threshold is 50. So result=$(( 100 * $used / $total )) should be just fine.CommentedApr 3, 2014 at 22:44
    5

    From the link you provided, I see the below line.

    result=$(echo "$used / $total * 100" |bc -l|cut -c -2) 

    As per @Graeme's comment, change the above line to below.

    result=$(echo "$used / $total * 100" |bc -l) 

    Now, after adding the above line, we have to change the output of the result to integer as below.

    result1=${result/.*} 

    I guess in one of the machines where the error occurs, this output is not an integer. Just convert the output of result to integer so that you can handle such cases. Add the below line after you calculate the result.

    result1=${result/.*} 

    And instead of result change the variable names as result1 inside the if loops, and the error won't occur.

    I suspect, the cut -c -2 attributes to the error mostly since it is cutting the first 2 characters only. What if result has just one character? Suppose if result is 1.23456, the above cut will result in 1. as the value for result which obviously is the cause of the integer expected error.

    The reason it is working fine in the remaining servers is because it has not encountered a case where the result variable has just a single digit. It is highly likely to fail in the remaining servers too if the result is a single digit variable (something like I mentioned in the above example).

    2
    • ${result%%.*} would be the correct expansion to remove the decimal point here. But note that the cut -c -2 will also cause issues with numbers of 100 or more, so it is safer to drop it completely.
      – Graeme
      CommentedApr 3, 2014 at 17:49
    • @Graeme, I missed that. I should have made the changes in that line :)
      – Ramesh
      CommentedApr 3, 2014 at 18:33
    0

    So I don't know how to use awk very well at all. But I do know that what's going on in the script you linked is a lot of nonsense and that something like the following should work. I'm sorry I can't write this out perfectly well, but since you're already calling awk - twice it seems - you should be using something like this.

    _chkmem() { return $( free -m | grep "buffers/cache" awk '{ percent = ( $3 / ( $3 + $4 ) ) * 100 warn = '"${warnlevel?No warning level specified!}"' < percent ? WARNING : OK crit = '"${critical?No critical level specified!}"' < percent ? CRITICAL : $warn print "Mem $crit : $percent% used" if ( $crit != OK ) exit 1 }') } _chkmem || exit 1 

      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.