User Tools

Site Tools


2018numeric_cmp

Comparison operators in BASH

The multiple constructs that are available in BASH can lead to confusion.

Brackets

  • Single brackets [ ] are generally OK, but might allow some syntax to be interpreted as commands (thus causing errors)
  • Double brackets [[ ]] have less parsing, so are generally safer to use.

Correct Numeric Comparisons

You must use the flag operators, or the symbolic operators inside double parentheses, to correctly compare values numerically. For example, say a=2 and b=10:

  • [ 2 -lt 10 ] is TRUE
  • [[ 2 -lt 10 ]] is TRUE
  • [[ 2 -ge 10 ]] is FALSE
  • (( 2 < 10 )) is TRUE

Incorrect Numeric Comparisons (lexicographic order)

What results in an alphanumeric comparison (which has unexpected behavior), or a syntax error (which you may overlook) is the following:

  • [[ 2 < 10 ]], alphanumerically FALSE
  • [ 2 < 10 ], error; also FALSE.

Importance of Testing

Whenever I have a question about a confusing syntax issue, I write a short test script to flesh out all the possibilities. To distinguish between the correct, incorrect, and error-producing constructs, I wrote a script that produces this table:

Syntax Output Error
Numeric comparisons: 2 less than 10 should be TRUE
[ 2 < 10 ] FALSE 10: No such file or directory
[ 2 \< 10 ] FALSE
[[ 2 < 10 ]] FALSE
[[ 2 -lt 10 ]] TRUE
[ 2 -lt 10 ] TRUE
[ "2" -lt "10" ] TRUE
test 2 -lt 10 TRUE
(( 2 < 10 )) TRUE
(( 2 -lt 10 )) FALSE ((: 2 -lt 10 : syntax error (error token is "10 ")
Numeric comparisons: 10 less than 2 should be FALSE
[ 10 < 2 ] FALSE 2: No such file or directory
[ 10 \< 2 ] TRUE
[[ 10 < 2 ]] TRUE
[[ 10 -lt 2 ]] FALSE
[ 10 -lt 2 ] FALSE
test 10 -lt 2 FALSE
(( 10 < 2 )) FALSE
(( 10 -lt 2 )) FALSE ((: 10 -lt 2 : syntax error (error token is "2 ")

This script is:

#!/usr/bin/env bash
# numeric_comparisons.bash - 
# Distinguish valid numeric versus 
# lexicographic comparison constructs.
###
 
a=2
b=10
echo "Numeric comparisons: $a less than $b should be TRUE"
echo "------------------------------------"
echo -ne "[ $a < $b ]\t"
[ $a < $b ] && echo "TRUE" || echo "FALSE"
 
echo -ne "[ ! $a -lt $b ]\t"
[ ! $a -lt $b ] && echo "TRUE" || echo "FALSE"
 
echo -ne "[ $a \< $b ]\t"
[ $a \< $b ] && echo "TRUE" || echo "FALSE"
 
echo -ne "[[ $a < $b ]]\t"
[[ $a < $b ]]  && echo "TRUE" || echo "FALSE"
 
echo -ne "[[ $a -lt $b ]]\t"
[[ $a -lt $b ]]  && echo "TRUE" || echo "FALSE"
 
echo -ne "[ $a -lt $b ]\t"
[ $a -lt $b ] && echo "TRUE" || echo "FALSE"
 
echo -ne "[ \"$a\" -lt \"$b\" ]\t"
[ "$a" -lt "$b" ] && echo "TRUE" || echo "FALSE"
 
echo -ne "test $a -lt $b\t"
test $a -lt $b  && echo "TRUE" || echo "FALSE"
 
echo -ne "(( $a < $b ))\t"
(( $a < $b ))  && echo "TRUE" || echo "FALSE"
 
echo -ne "(( $a -lt $b ))\t"
(( $a -lt $b ))  && echo "TRUE" || echo "FALSE"
 
# Reverse the values of a and b. 
# This should reverse the outcomes
# of the above commands.
a=10
b=2
echo "Numeric comparisons: $a less than $b should be FALSE"
echo "------------------------------------"
echo -ne "[ $a < $b ]\t"
[ $a < $b ] && echo "TRUE" || echo "FALSE"
 
echo -ne "[ $a \< $b ]\t"
[ $a \< $b ] && echo "TRUE" || echo "FALSE"
 
echo -ne "[[ $a < $b ]]\t"
[[ $a < $b ]]  && echo "TRUE" || echo "FALSE"
 
echo -ne "[[ $a -lt $b ]]\t"
[[ $a -lt $b ]]  && echo "TRUE" || echo "FALSE"
 
echo -ne "[ $a -lt $b ]\t"
[ $a -lt $b ] && echo "TRUE" || echo "FALSE"
 
echo -ne "test $a -lt $b\t"
test $a -lt $b  && echo "TRUE" || echo "FALSE"
 
echo -ne "(( $a < $b ))\t"
(( $a < $b ))  && echo "TRUE" || echo "FALSE"
 
echo -ne "(( $a -lt $b ))\t"
(( $a -lt $b ))  && echo "TRUE" || echo "FALSE"
2018numeric_cmp.txt · Last modified: 2018/09/07 14:02 by david