different result for [[ ]] and [] string comparator "<"

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

Upvotes: 2

Views: 93

Answers (2)

Keith Thompson
Keith Thompson

Reputation: 263477

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 >.

Upvotes: 5

Charles Duffy
Charles Duffy

Reputation: 295619

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.

Upvotes: 2

Related Questions