14

I was writing a bash script and suddenly this behaviour started:

[[ 1 < 2 ]]; echo $?  # outputs 0
[[ 2 < 13 ]]; echo $? # outputs 1

but -lt works soundly:

[[ 1 -lt 2 ]]; echo $?  # outputs 0
[[ 2 -lt 13 ]]; echo $? # outputs 0

did I accidentally overwrite < somehow?

here is a script I wrote to test this behaviour:

#!/bin/bash

for a in {1..5}
do
    for b in {1..20}
    do
        [[ $a < $b ]] && echo $a $b
    done

    echo
done

here is the output:

1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
1 13
1 14
1 15
1 16
1 17
1 18
1 19
1 20

2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 20

3 4
3 5
3 6
3 7
3 8
3 9

4 5
4 6
4 7
4 8
4 9

5 6
5 7
5 8
5 9

changing < to -lt in the script gives normal output (5 10 shows up for example).

Rebooting did not change anything.

My bash version is GNU bash, version 4.3.42(1)-release (x86_64-pc-linux-gnu). I am on Ubuntu 15.10. I don't know what other information is relevant here.

  • 16
    with < operation, you are making a string comparison, whereas -lt operator is numeric comparison, If you look at the results you have listed, you will realize it. Numerically 2 is less than 10, alphabetically, the other way around. – MelBurslan May 31 '16 at 18:50
51

From the bash man page.

When used with [[, the < and > operators sort lexicographically using the current locale.

From the output, it appears to be working as designed.

  • 35
    In other words, read the man page before you assume you have found a bug. ;) – Wildcard May 31 '16 at 19:10
  • True. Perhaps the script i originally was working on started actually working 'correctly' (as in failing [[ $myvar < 13 ]]) when i noticed this behavior then. Is there anything I should do to this question now? Do we on this site change the title to include [solved] or something? Should the title be changed anyway to something more descriptive? – snail-on-a-quest May 31 '16 at 19:18
  • 2
    No, don't change the title of the question. The check mark next to this answer is enough to indicate the question has been solved. – saiarcot895 May 31 '16 at 20:22
  • 14
    @Wildcard The OP doesn't assume they found a bug. They explicitly suggest that perhaps they have done something to alter the behavior. Even the title assumes as much! – jpmc26 Jun 1 '16 at 1:04
6

How about:

for a in {1..5}; 
do     
  for b in {1..20};     
  do         
    (( $a < $b )) && echo $a $b
  done      
  echo
done

According to http://www.tldp.org/LDP/abs/html/dblparens.html

Similar to the let command, the (( ... )) construct permits arithmetic expansion and evaluation. In its simplest form, a=$(( 5 + 3 )) would set a to 5 + 3, or 8. However, this double-parentheses construct is also a mechanism for allowing C-style manipulation of variables in Bash, for example, (( var++ )).

  • 2
    You are missing the point of the question - it is not "how can I compare those values?" but "why does it behave the way it does?". – guntbert May 31 '16 at 20:09
  • 7
    This was already answered. But as he wanted to use an arithmetic expression it might be worth pointing out that there exist constructs that allow you to use those in shell. – PaulSmecker May 31 '16 at 20:17
3

Firstly, [[ is not POSIX and should be avoided.

Secondly, if you wish to use < as part of an arithmetic test you can do this, but with different syntax:

if [ $((2 < 13)) = 1 ]
then
  echo '2 is less than 13'
else
  echo '2 is greater or equal to 13'
fi

Or:

if expr 2 '<' 13
then
  echo '2 is less than 13'
else
  echo '2 is greater or equal to 13'
fi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.