Bash: Numeric comparison

From FVue
Jump to: navigation, search

Problem

The following tests – using greater than (>) – do not work:

# Redirects to file `5'.  Returns true unexpected.
[ 3 > 5 ] && echo true     # WRONG

# Does string - not numeric - comparison.  Returns true unexpected.
[[ 5 > 34 ]] && echo true  # WRONG

Solutions

Solution 1: Arithmetic command: ((..))

Do arithmetic evaluation, using the `((..))' syntax:

((3 > 5)) && echo true

Compared with the other solutions, this is executed fastest, see #Time comparison.

This command is available since bash-2.0-beta2.

Solution 2: Arithmetic binary operators: -eq, -ne, -lt, -le, -gt, -ge

Use the -eq, -ne, -lt, -le, -gt, or -ge arithmetic binary operators for numeric comparison. For example:

[ 3 -gt 5 ] && echo true
[[ 5 -gt 34 ]] && echo true

Time comparison

When comparing execution speed of the different solutions, ((..)) is executed fastest, followed by [[..]] and finally [..]:

                                             time
           ------------------------------------------------------------------------
                           real [%]                   real [s]   user [s]   sys [s]
           ----------------------------------------   --------   --------   -------
           0                                    100
           ----------------------------------------
((..))     ############################                2.001      1.960      0.044

[[..]]     ###############################             2.149      2.092      0.056

 [..]      ########################################    2.810      2.704      0.104

           ----------------------------------------   --------   --------   -------

Table 1: Time consumed doing 2,000 numeric comparisons. See #Appendix A: time_numeric.sh for the code used.

See also

BashPitfalls - Greg's Wiki
Comprehensive list of bash pitfalls, including this numeric comparison one.

Appendix A: time_numeric.sh

MAX=20000
echo bash-$BASH_VERSION
echo
echo '((..))'

f() {
    local i
    for (( i=MAX; i > 0; i-- )); do
        ((3 > 5))
    done
}
time f

echo
echo '[[..]]'

f() {
    local i
    for (( i=MAX; i > 0; i-- )); do
        [[ 3 -gt 5 ]]
    done
}
time f

echo
echo '[..]'

f() {
    local i
    for (( i=MAX; i > 0; i-- )); do
        [ 3 -gt 5 ]
    done
}
time f

Example output:

$ . time_numeric.sh 
bash-3.2.39(1)-release

((..))

real	0m2.001s
user	0m1.960s
sys	0m0.044s

[[..]]

real	0m2.149s
user	0m2.092s
sys	0m0.056s

[..]

real	0m2.810s
user	0m2.704s
sys	0m0.104s

Comments

blog comments powered by Disqus