2

I was doing some tests, and I couldn't understand why there two results are different. The first one seems correct, since in a crescent ordenation, the character 'f' comes first than 'F'

$ [[ "Foo" < "foo" ]]
$ echo $?
1

So why this one is incorrect?

$ [ "Foo" \< "foo" ]
$ echo $?
0
  • 1
    [The POSIX `test` standard](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html) doesn't specify `<` **at all**. There's no behavior it's guaranteed to have, so if your goal is portability, you absolutely shouldn't use it. – Charles Duffy Nov 29 '16 at 17:11
  • @CharlesDuffy: But if you're using bash, you can reasonably rely on the features it provides. – Keith Thompson Nov 29 '16 at 17:29
  • 1
    @KeithThompson, sure, but if you're exclusively targeting bash, you should be using `[[ ]]` (and not including the `sh` tag on your questions). – Charles Duffy Nov 29 '16 at 17:29

2 Answers2

5

Both [[ and [ are built into bash. [ is equivalent to the test command, also a builtin. (Well, almost equivalent; [ requires a matching ], test doesn't.)

According to the bash manual:

When used with test or [, the < and > operators sort lexicographically using ASCII ordering.

(Bourne shell builtins are documented here).

But the expression in [[ ... ]] follows the rules of Bash conditional expressions:

When used with [[, the < and > operators sort lexicographically using the current locale. The test command uses ASCII ordering.

(There's another test / [ command provided as part of the GNU coreutils package, typically /usr/bin/test. This command doesn't provide < and > operators, which are not specified by POSIX. The external command should be irrelevant if you're using bash, unless you explicitly give the full path /usr/bin/test.)

Your question is tagged both "bash" and "sh". If you're using bash, you should probably use the bash-specific [[ feature rather than [. If you want greater portability (e.g., if your script might be used with a shell other than bash), you can't rely on the [[ builtin, and you can't assume that [ or test supports < and >.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
2

The BSD test implementation of <[1], like the bash-builtin one, is not character-collation-order aware; it refers only to "the binary value" of the characters in question.

The bash [[ ]] implementation of < is characterset-aware: It honors the current language/locale's selected collation order.

If you set LC_COLLATE=C (specifying ASCII sort order), then [[ ]] will do the same:

$ (export LC_COLLATE=C; [[ "Foo" < "foo" ]]; echo $?)
0

[1] - > is not a POSIX-standardized test operator, so all answers must be in the context of a specific implementation.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • There are two distinct GNU implementations of `test` / `[`. One is an external command, part of the coreutils package, but the relevant one here is the bash builtin command. The coreutils `test` command does not provide `<` and `>` operators. – Keith Thompson Nov 29 '16 at 17:26
  • @KeithThompson, hmm, you're right -- it's a BSD one I was looking at the documentation for that does provide `<` and `>`. – Charles Duffy Nov 29 '16 at 17:28