What's the difference between [ and [[ in Bash?

Learn what's the difference between [ and [[ in bash? with practical examples, diagrams, and best practices. Covers bash development techniques with visual explanations.

Bash Brackets: Understanding the Difference Between [ and [[

A visual representation of two different types of brackets, one single and one double, symbolizing the distinction between Bash's [ and [[ commands.

Explore the nuances of [ (test) and [[ (conditional expression) in Bash scripting, including their syntax, capabilities, and when to use each for robust shell scripts.

In Bash scripting, [ and [[ are both used for evaluating conditional expressions. While they might appear similar, they have fundamental differences that impact how your scripts behave, especially concerning string comparisons, pattern matching, and error handling. Understanding these distinctions is crucial for writing reliable and secure shell scripts.

The [ Command: A POSIX Standard Utility

The [ command, also known as test, is a standard utility specified by POSIX. It behaves like any other command in Bash, meaning it requires spaces around its arguments and the closing ] is a mandatory argument. Because it's a regular command, it performs word splitting and pathname expansion on its arguments, which can lead to unexpected behavior if variables are not properly quoted.

# Basic usage of [
my_var="hello world"

# Correct usage with quoting
if [ "$my_var" = "hello world" ]; then
  echo "[ : Quoted variable matches!"
fi

# Incorrect usage without quoting - will cause an error due to word splitting
# if [ $my_var = "hello world" ]; then
#   echo "This will likely fail"
# fi

# Numeric comparison
num1=10
num2=5
if [ $num1 -gt $num2 ]; then
  echo "[ : 10 is greater than 5"
fi

Examples demonstrating the [ command with string and numeric comparisons.

The [[ Keyword: Bash's Enhanced Conditional Expression

The [[ keyword is a Bash-specific extension, not a separate command. It's a compound command similar to if or for. This distinction is important because [[ does not perform word splitting or pathname expansion on its arguments. This makes it generally safer and easier to use, as you don't always need to quote variables within [[ (though it's still good practice for clarity). It also offers enhanced features like regular expression matching and logical operators (&&, ||).

# Basic usage of [[
my_var="hello world"

# No need for quoting (though still good practice)
if [[ $my_var = "hello world" ]]; then
  echo "[[ : Unquoted variable matches!"
fi

# Regular expression matching
if [[ "$my_var" =~ ^hello.*ld$ ]]; then
  echo "[[ : Variable matches regex!"
fi

# Logical operators
num=15
if [[ $num -gt 10 && $num -lt 20 ]]; then
  echo "[[ : Number is between 10 and 20"
fi

Examples showcasing [[ with string comparison, regex, and logical operators.

flowchart TD
    A[Start]
    A --> B{Conditional Check}
    B -->|`[` Command| C[Standard POSIX `test` utility]
    C --> D{Word Splitting & Pathname Expansion?}
    D -->|Yes| E["Requires Quoting (`"$VAR"`)"]
    D -->|No| F["Limited Features (no regex, `&&`, `||`)"]
    B -->|`[[` Keyword| G[Bash-specific Compound Command]
    G --> H{Word Splitting & Pathname Expansion?}
    H -->|No| I["Less Need for Quoting (`$VAR` often fine)"]
    H -->|Yes| J["Enhanced Features (regex, `&&`, `||`)"]
    E --> K[End]
    F --> K[End]
    I --> K[End]
    J --> K[End]

Decision flow for choosing between [ and [[ in Bash.

Key Differences Summarized

To help solidify your understanding, here's a summary of the main differences between [ and [[:

A table comparing the features and behaviors of Bash's [ and [[ commands, highlighting differences in POSIX compliance, word splitting, regex support, and logical operators.

Comparison of [ vs. [[ features.

When to Use Which

Generally, for modern Bash scripting, [[ is the preferred choice due to its enhanced features and safer handling of variables. It reduces the likelihood of subtle bugs related to word splitting and provides more powerful conditional checks.

However, there are specific scenarios where [ might be necessary:

  • Portability: If your script needs to run on systems that might not have Bash (e.g., sh or other POSIX-compliant shells), [ is the more portable option.
  • Simplicity: For very basic, straightforward checks where you're confident in quoting, [ works perfectly fine.

For most new Bash scripts, default to [[ unless portability to non-Bash shells is a strict requirement.