[ is an alias for the
test command. Unix Version 6 had an
if command, but Version 7 (1979) came with the new Bourne shell that had a few programming constructs including the if-then-else-elif-fi construct, and Unix version 7 added a
test command that performed most of the "tests" that were carried out by the
if command in older versions.
[ was made an alias to
test and both were made built into the shell in Unix System III (1981). Though it should be noted that some Unix variants did not have a
[ command until later after that.
[ is a command to do "tests", there's no assignment that that command does, so there's no reason to disambiguate between an assignment and equality operator, so the equality operator is
== is only supported by a few recent implementations of
[ (and is just an alias for
[ is nothing more than a command, it is parsed the same way as any other command by the shell.
Specifically, in your example,
$a, because it is not quoted, would be split into several words according to the usual rules of word splitting, and each word would undergo filename generation aka globbing to result into possibly more words, each of those words resulting in a separate argument to the
z* would be expanded to the list of filenames in the current directory starting with
So for instance, if
b* = x, and there are
b2 files in the current directory, The
[ command would get 9 arguments:
[ parses its arguments as a conditional expression. Those 9 arguments don't add up to a valid conditional expression, so it would probably return an error.
[[ ... ]] construct was introduced by the Korn shell. I don't know much about the early history of the Korn shell, but it's probably safe to assume that the feature was introduced sometime in the mid-80's.
Beside ksh (all implementations),
[[...]] is also supported by bash and zsh, but all three implementations are different and there are differences between each version of a same shell though the changes are generally backward compatible (a notable exception being bash's
=~ operator that has been known to break a few scripts after a certain version when its behavior changed).
[[...]] is not specified by POSIX, or Unix or Linux (LSB). It has been considered for inclusion a few times, but not included as the common functionality of it supported by the major shells is already covered by the
[ command and the
[[ ... ]] construct makes up a command. That is, it has an exit status (which is its most important asset as it is the result of evaluating the conditional expression), you may pipe it to another command (though it would not be useful), and generally use it wherever you would use any other command (inside the shell only, as it's a shell construct) but it is not parsed like a normal simple command. What's inside is parsed by the shell as a conditional expression and the usual rules of word splitting and filename generation apply differently.
[[ ... ]] does know about
== from the start and is equivalent to
=. A blunder of ksh's though (and is causing confusion and many bugs) is that the
== are not an equality operator but a pattern matching operator (though the matching aspect can be disabled with quoting but with unclear rules that differ from shell to shell).
In your code above
[[ $a == z* ]], the shell would parse that into several tokens in rules similar to the usual ones, recognize it as a pattern matching comparison, treat
z* as a pattern to match against the content of the
Generally, it's harder to shoot yourself in the foot with
[[ ... ]] than it is with the
[ command. But a few rules like
- always quote variables
- never use the
-o operator (use several
[ commands and the
|| shell operators)
[ reliable with POSIX shells.
[[...]] in different shells support extra operators like
-nt, regexp matching operators... but the list and behavior varies from shell to shell and version to version.
So unless you know what shell and minimum version of it your script will ever be interpreted by, it's probably safer to stick with the standard