Comparing two strings containing '_' lexicographically in bash

Viewed 175

I need to compare strings in a bash script lexicographically. The problem is that it seems that bash totally ignores '_' characters, as if they were not there at all. In the ascii code table '_' is between the upper case letters and the lower case letters so I'd assume that A-Z < _ < a-z, and this is what actually happens on Mac OS, but not on Debian:

1   $ if [[ "ab" < "a_" ]]; then echo 1; fi
2   $ if [[ "ab" < "a_a" ]]; then echo 1; fi
3   $ if [[ "ab" < "a_c" ]]; then echo 1; fi
    1
4   $ if [[ "aZ" < "a_" ]]; then echo 1; fi
    $

Command #3 should be false as well, because '_' < 'b', while command #4 should be true because '_' > 'Z'.

The only logical explanation to me is that the '_' characters are simply omitted in Debian bash, so "ab" < "a" -> false, "ab" < "aa" -> false, "ab" < "ac" -> true, "aZ" < "a" -> false is what really is getting evaluated.

Is there any way in Debian bash to compare these strings treating their '_' characters as their ascii code would suggest?

Thanks

1 Answers

As pointed out in the comments, the [[ < ]] operator depends on your current locale. This is also documented in bash's manual:

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

You can check your current locale using the command locale. When you run this command on your Mac OS and Debian you should get different results.

You can overwrite your system's locale for your script using export LC_ALL=.... The locale for sorting by ascii codes is C.

$ export LC_ALL=en_US.UTF-8; [[ ab < a_c ]]; echo $?
0
$ export LC_ALL=C; [[ ab < a_c ]]; echo $?
1
Related