← Back to Bash Course | Chapter 3: Control Flow | Lesson 6 of 14

[[ ]] Extended Test Operator

[[ ]] is Bash's improved version of [ ] that is more forgiving about quoting and adds extra features like pattern matching and regular expressions.

[[ ]] Basics and Safer Quoting

[[ expression ]] behaves like [ ] for basic comparisons but is more forgiving: unquoted variables inside it are not subject to word splitting or globbing, which avoids many [ ] pitfalls. It is a Bash keyword, not a separate command, so its parsing rules differ from [ ].

Example: [[ ]] Basics and Safer Quoting

bash
#!/bin/bash
name=""
if [[ $name = "" ]]; then
    echo "name is empty, and this worked without quoting"
fi

Logical Operators Inside [[ ]]

[[ ]] allows && and || directly inside the double brackets to combine multiple conditions in one expression, which is cleaner than [ ]'s reliance on -a/-o (which are also deprecated). This makes compound conditions much more readable.

Example: Logical Operators Inside [[ ]]

bash
#!/bin/bash
age=25
has_id=true
if [[ $age -ge 18 && $has_id = true ]]; then
    echo "Entry allowed"
fi

Glob Pattern Matching with ==

Inside [[ ]], an unquoted pattern on the right side of == or != is matched as a glob (wildcard) pattern rather than a literal string, so * matches any sequence of characters. Quoting the pattern turns off this special matching and forces a literal comparison instead.

Example: Glob Pattern Matching with ==

bash
#!/bin/bash
filename="report.txt"
if [[ $filename == *.txt ]]; then
    echo "It's a text file"
fi
if [[ $filename == "*.txt" ]]; then
    echo "This won't print, because the pattern is quoted (literal)"
fi

Regex Matching with =~

[[ str =~ regex ]] tests str against a POSIX extended regular expression, and if it matches, the full match and any parenthesized capture groups are stored in the BASH_REMATCH array (BASH_REMATCH[0] is the whole match, [1] the first group, etc.). The regex itself should generally be left unquoted or stored in a variable first for portability.

Example: Regex Matching with =~

bash
#!/bin/bash
email="[email protected]"
if [[ $email =~ ^([a-z]+)@([a-z.]+)$ ]]; then
    echo "Full match: ${BASH_REMATCH[0]}"
    echo "Username: ${BASH_REMATCH[1]}"
    echo "Domain: ${BASH_REMATCH[2]}"
fi
Common Mistakes
  1. Assuming [[ ]] is fully POSIX-portable like [ ]; it is a Bash (and some other modern shells') extension, so scripts meant to run under plain sh should stick to [ ].
  2. Forgetting that inside [[ ]], < and > really do compare strings alphabetically without needing escaping (unlike inside [ ] where they redirect); numeric comparison still needs -lt/-gt etc.
  3. Quoting the pattern on the right side of == when using it for glob matching, e.g. [[ $file == "*.txt" ]]; quoting turns it into a literal string comparison instead of a wildcard match.
Chapter Summary
  • [[ ]] does not word-split or glob-expand unquoted variables inside it, so [[ $name = value ]] is safe even without quotes.
  • [[ ]] supports && and || directly inside the brackets, unlike [ ] which needs -a/-o or separate test invocations.
  • [[ str == pattern ]] supports glob-style wildcard matching when the right-hand pattern is unquoted.
  • [[ str =~ regex ]] performs POSIX extended regular expression matching, storing captured groups in the BASH_REMATCH array.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.