7

I was looking at discussion between Kusalananda and xhienne here, where it's mentioned [ "" -ge 2 ] not being a valid test producing an error in bash --posix and other POSIX-compliant shells.

bash-4.3$ [ "" -gt 10 ]
bash: [: : integer expression expected
bash-4.3$ [ '' -gt 10 ]
bash: [: : integer expression expected

All good there. Out of curiosity, I tried the same with [[.

bash-4.3$ [[ "" -gt 10 ]] && echo "YES"
bash-4.3$ [[ "" -gt 0 ]] && echo "YES"
bash-4.3$ [[ "" -gt -1 ]] && echo "YES"
YES
bash-4.3$ [[ "" -eq 0 ]] && echo "YES"
YES

As you can see, no errors and it's actually evaluated as numeric expression with "" being equal to 0. So what exactly is happening here ? Is [[ simply being inconsistent with the old test or POSIX ? Is it simply performing string comparison rather than numeric comparison ?

14

One difference between [ and [[ is that [ does not do arithmetic evaluation but [[ does:

$ [ "2 + 2" -eq 4 ] && echo yes
bash: [: 2 + 2: integer expression expected
$ [[ "2 + 2" -eq 4 ]] && echo yes
yes

The second subtlety is that, wherever arithmetic evaluation is performed under bash, empty strings evaluate to 0. For example:

$ x=""; echo $((0 + x))
0
$ [[ "" -eq 0 ]] && echo yes
yes

Documentation

From man bash:

Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax. The value of a variable is evaluated as an arithmetic expression when it is referenced, or when a variable which has been given the integer attribute using declare -i is assigned a value. A null value evaluates to 0. A shell variable need not have its integer attribute turned on to be used in an expression. [Emphasis added]

Aside: Security Issues

Note that bash's arithmetic evaluation is a potential security issue. For example, consider:

x='a[$(rm -i *)]'
[[ x -eq 0 ]] && echo yes

With the -i option, the above is safe but the general lesson is not to use bash's arithmetic evaluation with un-sanitized data.

By contrast, with [, no arithmetic evaluation is performed and, consequently, the command never attempts to delete files. Instead, it safely generates an error:

$ x='a[$(rm -i *)]'
$ [ "$x" -eq 0 ] && echo yes
bash: [: a[$(rm -i *)]: integer expression expected

For more on this issue, see this answer.

2
  • I see. [[ does arithmetic evaluation, that's what was missing. I think you should put that as the top point Oct 8 '17 at 20:24
  • @SergiyKolodyazhnyy Very good. I re-ordered the two points in the answer.
    – John1024
    Oct 8 '17 at 20:29
3

Yes, posix test ([) would not convert an string to a number on numerical comparisons:

$ sh -c '[ 2+2 -eq 4 ]'
sh: 1: [: Illegal number: 2+2

$  dash -c '[ 2+2 -eq 4 ]'
dash: 1: [: Illegal number: 2+2

$ bash -c '[ 2+2 -eq 4 ] && echo "YES"'
bash: line 0: [: 2+2: integer expression expected

However, not all shells work in the same way:

$ ksh -c '[ 2+2 -eq 4 ] && echo "YES"'
YES

Usual workaround

Make sure that a null or empty value is converted to 0 (works on most shells)

$ dash -c 'a=""; [ "${a:-0}" -gt 3 ] && echo "YES"'

Use arithmetic

Use arithmetic expansion ( may also convert values as 2+2 in some shells (not dash) )

$ dash -c 'a=""; [ "$((a+0))" -gt -3 ] && echo "YES"'
YES

Use [[

The use of the [[ test will convert most strings that would become a number (even if not wanted) in shells that allow [[:

$ [[ "2+2" -gt 3 ]] && echo "YES"
YES
4
  • I was looking more at the "why" of such behavior occurs in [[,which your answer doesn't seem to touch on, but still relevant information. I'm curious why ksh implements [ that way. Oct 9 '17 at 6:14
  • Well, it does: convert most strings that would become a number. That is the reason. As for the philosophical reason on the mind of the programmer that implemented it in such a way, you should ask him. @SergiyKolodyazhnyy
    – ImHere
    Oct 9 '17 at 6:31
  • lol, trust me, if I had David Korn's email, I would XD Oct 9 '17 at 6:41
  • This may be still valid ;-) or search github. @SergiyKolodyazhnyy
    – ImHere
    Oct 9 '17 at 7:06

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .