Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Is there is any difference between these two.

[[ $a == z* ]]

and

[ $a == z* ] 

Can I have an example where they would have different outputs?

Furthermore, how does the working of [[ ]] differs from [ ]?

share|improve this question
add comment

3 Answers

up vote 18 down vote accepted

The difference between [[ … ]] and [ … ] is mostly covered in using single or double bracket - bash. Crucially, [[ … ]] 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:

  1. Parse the command: this is the [[ … ]] conditional construct around the conditional expression $a == z*.
  2. Parse the conditional expression: this is the == binary operator, with the operands $a and z*.
  3. Expand the first operand into the value of the variable a.
  4. Evaluate the == operator: test if the value of the variable a matches the pattern z*.
  5. Evaluate the conditional expression: its result is the result of the conditional operator.
  6. The command is now evaluated, its status is 0 if the conditional expression was true and 1 if it was false.

Here's how [ $a == z* ] is evaluated:

  1. Parse the command: this is the [ command with the arguments formed by evaluating the words $a, ==, z*, ].
  2. Expand $a into the value of the variable a.
  3. Perform word splitting and filename generation on the parameters of the command.
    • For example, if the value of a is the 6-character string foo b* (obtained by e.g. a='foo b*') and the list of files in the current directory is (bar, baz, qux, zim, zum), then the result of the expansion is the following list of words: [, foo, bar, baz, ==, zim, zum,]`.
  4. Run the command [ with the parameters obtained in the previous step.
    • With the example values above, the [ command complains of a syntax error and returns the status 2.
share|improve this answer
add comment

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

Note that test aka [ 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 =).

Because [ 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 [ command.

Similarly, z* would be expanded to the list of filenames in the current directory starting with z.

So for instance, if $a is b* = x, and there are z1, z2, b1 and b2 files in the current directory, The [ command would get 9 arguments: [, b1, b2, =, x, ==, z1, z2 and ].

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

The [[ ... ]] 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 case-in-esac construct.

The whole [[ ... ]] 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 = and == 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 a variable.

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 -a or -o operator (use several [ commands and the && and || shell operators)

Make [ 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 [ command.

share|improve this answer
    
Great info. Would you please explain why "never use the -a or -o operator"? –  grebneke Mar 1 at 21:13
    
@grebneke, try [ '!' = foo -o a = a ] in bash for instance. –  Stephane Chazelas Mar 2 at 9:38
add comment

both are used to evaluate expressions and [[ will not work with POSIX older bourn shell and [[ also supports pattern matching and regex. example try these

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"

share|improve this answer
    
Note that the Bourne shell is not POSIX, [[...]] supports regexps only in some versions of some shells, just like some versions of [ do support regexp matching. For arithemtic comparison, in those shells that support [[, you'd rather write (( n == 0 && y == 0)) –  Stephane Chazelas Nov 25 '12 at 22:04
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.