Is there is any difference between these two.
[[ $a == z* ]]
[ $a == z* ]
Can I have an example where they would have different outputs?
Furthermore, how does the working of
[[ ]] differs from
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.Sign up to join this community
The difference between
[[ … ]] and
[ … ] is mostly covered in Why does parameter expansion with spaces without quotes work inside double brackets "[[" but not inside single brackets "["?.
[[ … ]] is special syntax, whereas
[ is a funny-looking name for a command.
[[ … ]] has special syntax rules for what's inside,
[ … ] doesn't.
With the added wrinkle of a wildcard, here's how
[[ $a == z* ]] is evaluated:
[[ … ]]conditional construct around the conditional expression
$a == z*.
==binary operator, with the operands
==operator: test if the value of the variable
amatches the pattern
[ $a == z* ] is evaluated:
[command with the arguments formed by evaluating the words
$ainto the value of the variable
ais the 6-character string
foo b*(obtained by e.g.
a='foo b*') and the list of files in the current directory is (
zum), then the result of the expansion is the following list of words:
[with the parameters obtained in the previous step.
[command complains of a syntax error and returns the status 2.
[[ $a == z* ]], at step 3, the value of
a does not undergo word splitting and filename generation, because it's in a context where a single word is expected (the left-hand argument of the conditional operator
==). In most cases, if a single word makes sense at that position then variable expansion behaves like it does in double quotes. However, there's an exception to that rule: in
[[ abc == $a ]], if the value of
a contains wildcards, then
abc is matched against the wildcard pattern. For example, if the value of
[[ abc == $a ]] is true (because the wildcard
* coming from the unquoted expansion of
[[ abc == "$a" ]] is false (because the ordinary character
* coming from the quoted expansion of
$a does not match
[[ … ]], double quotes do not make a difference, except on the right-hand side of the string matching operators (
[ 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 much later after that (up to the early 2000s on some BSDs where
sh is based on the Almquist shell (a
test builtin has always been included in
ash's source, but on those BSDs it was initially disabled)).
[ 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 probably around 1988 as
ksh86a in 1987 didn't have it while
ksh88 had it from the start.
Beside ksh (all implementations),
[[...]] is also supported by bash (since version 2.02) 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
=1. 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
-ooperator (use several
[commands and the
[ 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
[[...]] was added to bash in version
2.03 where it was changed,
[[ x = '?' ]] would return true while
[[ x == '?' ]] would return false. That is quoting did not prevent pattern matching when using the
= operator in those versions, but did when using