7
votes

I am trying to compare two strings in a bash script and I am getting very strange results.

if [[ "010" < "01." ]]; then echo "Wrong"; else echo "OK"; fi
if [[ "010" < "01.0" ]]; then echo "Wrong"; else echo "OK"; fi
if [ "010" \< "01." ]; then echo "Wrong"; else echo "OK"; fi
if [ "010" \< "01.0" ]; then echo "Wrong"; else echo "OK"; fi

Reading the documentation it seemed that [[ < ]] and [ \< ] should work the same, but they don't. It it seems that [[ < ]] works wrong when the strings don't have the same length. Am I missing something?

Edit: The expected result is 4 x OK. Tested on:

  • CentOS release 6.4 (Final) - GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) (OK Wrong OK OK)
  • Ubuntu 14.04.2 LTS - GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) (OK Wrong OK OK)
  • openSUSE 13.1 (Bottle) (x86_64) - GNU bash, version 4.2.53(1)-release (x86_64-suse-linux-gnu) (OK OK OK OK)
3
Could you please add the output of the script? - moffeltje
The 2nd says Wrong to me on GNU bash, version 4.3.39. - fedorqui 'SO stop harming'
I confirm strange behavior: output says: "OK, wrong, OK, OK"; while the expected output for me would have been "OK, wrong, OK, wrong"; since the values are sorted "01.", "010", "01.0" on my pc. - Chris Maes
note that the strange behavior only occurs for limit case sorting; looks like a different sorting algorithm is used when using single vs double brackets; is that possible? - Chris Maes
Looking at the ASCII table . comes before 0 so the expected order of strings should be 01., 01.0, 010 - Marin

3 Answers

1
votes

Here is the documentation from help test:

STRING1 > STRING2

True if STRING1 sorts after STRING2 lexicographically.

Taking your first if statement as an example:

if [[ "010" < "01." ]]; then echo "Wrong"; else echo "OK"; fi

In Bash the string "01." sorts lexicographically before the string "010" (you can test in other tools like Microsoft Excel), so the comparison returns false. This is the case for all 4 of your comparisons.

Note that adding an additional 0 to the end of "01." doesn't change the ordering versus "010", so you still get the same result.

0
votes

The reason might be that starting with bash 4.1 the < and > string comparison operators respect the locale.

So between two systems you can have the following differences:

  1. different locales - check by running locale (for a meaning of the different locale settings see https://unix.stackexchange.com/a/87763/122478)
  2. even if the locales are the same, shopt compat31 or compat32 might be switched on (bash 3.1 or 3.2 compatibility mode), which means that the string comparisons would not respect locale - check by running shopt

Further reading:

-1
votes

If you wan to compare integer you shall do this :

if [[ 10 < 1 ]]; then echo "10 < 1";else echo "10 > 1";fi 10 > 1

If you want to compare float you should look at this thread : How to do float comparison in Bash?

For your example :

echo "10 < 1.0" |bc return : 0

echo "10 > 1.0" |bc retunr :1