535

I looked at bash man page and the [[ says it uses Conditional Expressions. Then I looked at Conditional Expressions section and it lists the same operators as test (and [).

So I wonder, what is the difference between [ and [[ in Bash?

codeforester
  • 39,467
  • 16
  • 112
  • 140
bodacydo
  • 75,521
  • 93
  • 229
  • 319

4 Answers4

799

[[ is bash's improvement to the [ command. It has several enhancements that make it a better choice if you write scripts that target bash. My favorites are:

  1. It is a syntactical feature of the shell, so it has some special behavior that [ doesn't have. You no longer have to quote variables like mad because [[ handles empty strings and strings with whitespace more intuitively. For example, with [ you have to write

    if [ -f "$file" ]
    

    to correctly handle empty strings or file names with spaces in them. With [[ the quotes are unnecessary:

    if [[ -f $file ]]
    
  2. Because it is a syntactical feature, it lets you use && and || operators for boolean tests and < and > for string comparisons. [ cannot do this because it is a regular command and &&, ||, <, and > are not passed to regular commands as command-line arguments.

  3. It has a wonderful =~ operator for doing regular expression matches. With [ you might write

    if [ "$answer" = y -o "$answer" = yes ]
    

    With [[ you can write this as

    if [[ $answer =~ ^y(es)?$ ]]
    

    It even lets you access the captured groups which it stores in BASH_REMATCH. For instance, ${BASH_REMATCH[1]} would be "es" if you typed a full "yes" above.

  4. You get pattern matching aka globbing for free. Maybe you're less strict about how to type yes. Maybe you're okay if the user types y-anything. Got you covered:

    if [[ $ANSWER = y* ]]
    

Keep in mind that it is a bash extension, so if you are writing sh-compatible scripts then you need to stick with [. Make sure you have the #!/bin/bash shebang line for your script if you use double brackets.

See also

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 22
    Good, except [[ also exists in ksh and recent POSIX sh specifications. – Darron Aug 06 '10 at 21:56
  • 1
    FWIW, reference for the set of conditional expressions (like `-f`, `-z` etc) that can go inside `[` or `[[` is at [Bash Reference Manual: Bash Conditional Expressions](https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html#Bash-Conditional-Expressions) – ShreevatsaR May 02 '18 at 19:29
  • @Darron I'm using Ubuntu in a specific server and my sh (which is, in fact, dash version 0.5.8) does not support [[ – Henrique Dec 06 '19 at 21:27
  • 1
    @Darron In here https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#:~:text=2.4%20Reserved%20Words it exists, however, the behaviour is not specified so one cannot depend on it when POSIX compliance is necessary. – VaNa Oct 04 '21 at 12:29
46
  • [ is the same as the test builtin, and works like the test binary (man test)
    • works about the same as [ in all the other sh-based shells in many UNIX-like environments
    • only supports a single condition. Multiple tests with the bash && and || operators must be in separate brackets.
    • doesn't natively support a 'not' operator. To invert a condition, use a ! outside the first bracket to use the shell's facility for inverting command return values.
    • == and != are literal string comparisons
  • [[ is a bash
    • is bash-specific, though others shells may have implemented similar constructs. Don't expect it in an old-school UNIX sh.
    • == and != apply bash pattern matching rules, see "Pattern Matching" in man bash
    • has a =~ regex match operator
    • allows use of parentheses and the !, &&, and || logical operators within the brackets to combine subexpressions

Aside from that, they're pretty similar -- most individual tests work identically between them, things only get interesting when you need to combine different tests with logical AND/OR/NOT operations.

Walter Mundt
  • 24,753
  • 5
  • 53
  • 61
26

The most important difference will be the clarity of your code. Yes, yes, what's been said above is true, but [[ ]] brings your code in line with what you would expect in high level languages, especially in regards to AND (&&), OR (||), and NOT (!) operators. Thus, when you move between systems and languages you will be able to interpret script faster which makes your life easier. Get the nitty gritty from a good UNIX/Linux reference. You may find some of the nitty gritty to be useful in certain circumstances, but you will always appreciate clear code! Which script fragment would you rather read? Even out of context, the first choice is easier to read and understand.


if [[ -d $newDir && -n $(echo $newDir | grep "^${webRootParent}") && -n $(echo $newDir | grep '/$') ]]; then ...

or

if [ -d "$newDir" -a -n "$(echo "$newDir" | grep "^${webRootParent}")" -a -n "$(echo "$newDir" | grep '/$')" ]; then ...
Tino
  • 9,583
  • 5
  • 55
  • 60
Anthony Rutledge
  • 6,980
  • 2
  • 39
  • 44
  • 2
    Although the other answers are technically correct, this is the only one that's completely right. – Software Engineer Jun 20 '20 at 08:49
  • "The most important difference will be the clarity of your code.": No, the difference is that `[` is a command, while `[[` is a syntax element ("reserved word"). Thus the different parsing. – U. Windl Apr 07 '21 at 07:49
  • No? I am only speaking to the practical difference. `[[ ]]` is a short cut for `let`, if I am not mistaken. At the end of the day, true, there are syntactical differences, but for the layman, it's the ease of reading and maintainability that will matter most. Hence, this is why I say "most important," not "only" or "by the book specific" difference. – Anthony Rutledge Apr 07 '21 at 17:03
  • @AnthonyRutledge it's `(( ))` which is akin to `let`. But that's for arithmetic calculations, not just boolean logic. – Johan Boulé Mar 13 '23 at 16:28
  • @JohanBoulé I like the `(( ))` for doing arithmetic. – Anthony Rutledge Mar 14 '23 at 17:39
7

In bash, contrary to [, [[ prevents word splitting of variable values.

nbro
  • 15,395
  • 32
  • 113
  • 196
Xavier V.
  • 6,068
  • 6
  • 30
  • 35