Lexical v Arithemetic testing, Bash and Perl
Archive - Originally posted on "The Horse's Mouth" - 2007-12-11 08:36:38 - Graham EllisIf you tell a story against someone, best to be telling it against yourself!
One of our web servers (running standard, not our own software behind the scenes) has been having a problem with handling denial of service attacks which are coming in from time to time ... and I have a monitoring script running in bash which notices an overloaded system within a short time period, and takes appropriate action. That's done using the uptime command, and was originally written as follows:
buzz=`uptime`
busy=`echo $buzz | sed 's/.*load//' | awk '{print }' | tr , " "`
if [[ $busy > 4 ]] ; then
In other words .... get the statistics for the server loading, and if it's had more that 4 jobs in the queue for the last minute on average, take appropriate action.
The script has been running well - tripped occasionally when we've had an attack and had the server back quickly. But this morning I found the server dead and unreachable ... ("Don't Panic" comes to mind!).
Turns out that I have a coding error in my bash - did you notice? I used a > check which tests whether the loading is LEXICALLY greater than 4. Alas - my loadings had jumped in such a way that they were always lexically less than 4, even though they were arithmetically much higher:
06:44:00 up 7 days, 12:16, 1 user, load average: 0.13, 0.54, 0.35
06:45:00 up 7 days, 12:17, 1 user, load average: 1.75, 0.80, 0.45
06:46:05 up 7 days, 12:18, 1 user, load average: 26.47, 7.81, 2.86
06:48:44 up 7 days, 12:21, 1 user, load average: 123.63, 54.70, 21.22
So my trip had never been activated .... and once the loading gets up to that level the system is pretty well screwed!
Solution - change code into ...
buzz=`uptime`
busy=`echo $buzz | sed 's/.*load//' | awk '{print }' | tr , " " | tr . 0`
if [[ $busy -gt 4000 ]] ; then
and I now await the next attack to see how it copes. (Shell arithmetic is integer, so we have converted the floating loading!)
This is a tip for users of bash. Note that in Perl, the operators worth the other way around with gt being lexical and > being arithmetic. I'll use that, as I'm predominantly a Perl programmer, as my excuse!