1

I read somewhere that in a shell script the [..] construct like for example [ -e $HOME/temp ] is POSIX compliant. While the script [[..]] construct like [[ -e $HOME/temp ]] is not.

Is this true?

Apart from POSIX compliance is there something inherent advantageous which [..] has over [[..]]? Or vice-versa?

1

1 Answer 1

3

Yes, the [ utility also known as test is standard, you can find an HTML version of its POSIX 2024 specification on the OpenGroup website.

There was a proposal to specify ksh's [[...]] in the POSIX sh language but it was eventually rejected (downscaled to just adding a few extra operators to [ that are common to most implementations).

You'll see the rationale section stating:

The KornShell-derived conditional command (double bracket [[]]) was removed from the shell command language description in an early proposal. Objections were raised that the real problem is misuse of the test command ([), and putting it into the shell is the wrong way to fix the problem. Instead, proper documentation and a new shell reserved word (!) are sufficient. A later proposal to add [[]] in Issue 8 was also rejected because existing implementations of it were found to be error-prone in a similar way to historical versions of test, and there was also too much variation in behavior between shells that support it.

Some of the relevant differences between [[...]] and [:

  • combining more than one test in one invocation reliably is easier to do with [[...]] than with [...] (where the -a/-o operators are actually deprecated as they can't be used reliably), but using [ ... ] && [ ... ] || [ ... ] is fine and doesn't incur penalties as [ is invariably builtin which makes [[...]]'s own &&/|| redundant (and potentially confusing as precedence rules are different from the shell's &&/||).
  • [[ $string = $pattern ]] does actually pattern matching rather than equality comparison. That is redundant as well with the standard case construct, and source of bugs as people tend to think it's fine to leave variables unquoted inside [[...]] (and it often is) and forget to do [[ $string1 = "$string2" ]] when comparing strings for equality.
  • it gets worse with [[ $string =~ $pattern ]] which is done differently depending on the shell. bash and a few other shells made an unfortunate decision to have quoting influence the regex operation there which is wrong as regex syntax is not compatible with normal shell tokenisation (more details at How does storing the regular expression in a shell variable avoid problems with quoting characters that are special to the shell? and in the Austin Group bug mentioned above). The [ builtin of zsh and yash do have a =~ operator as well.
  • in most shells, the arithmetic operators of [[...]] interpret their operands as arithmetic expressions (which makes things like [[ $1 -eq $2 ]] a command injection vulnerability in most shells (and causes surprises when the numbers start with 0 which makes them interpreted as octal in some shells). While POSIX requires operands to those of [ to be treated as decimal integers.
  • the parsing rules in [[...]] are specific to the construct and vary from shell to shell, while [ is just a simple command so handled like any other command.

So [ is usually fine and to quote POSIX the real problem is misuse of the test command ([).

As long as you remember to quote variables and other expansions (as needed for all commands, not just [) and don't use the -a (and), -o (or) deprecated binary operators (and (...) which are not needed anyway once you can't combine more than one test), [ is just fine (and safer when doing number comparisons).

[[...]] can be nicer as it can make for shorter code, can allow one to skip quoting some expansions, but that's mostly syntactic sugar but at the expense of having to learn extra syntax and its quirks.

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.