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'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 :)

share|improve this question

3 Answers 3

up vote 3 down vote accepted

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).

share|improve this answer
    
${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 Apr 3 at 17:49
    
@Graeme, I missed that. I should have made the changes in that line :) –  Ramesh Apr 3 at 18:33

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.

share|improve this answer
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. –  Stéphane Chazelas Apr 3 at 22:44

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

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.