Bash Single vs. Double Square Brackets: Key Differences, Performance Impact, and Practical Examples


3 views

In bash scripting, both [ (single bracket) and [[ (double bracket) are used for conditional expressions, but they differ fundamentally in implementation and capabilities:

# Traditional test command (POSIX)
[ "$STRING" != "foo" ]

# Bash extended test construct
[[ $STRING != foo ]]
  • Parsing Behavior: [ is a builtin that behaves like a command (originally linked to /bin/[), while [[ is a bash keyword with special parsing rules
  • Word Splitting: [ requires quotes to prevent word splitting, whereas [[ handles variables more intelligently
  • Pattern Matching: [[ supports == with glob patterns and =~ for regex

Let's measure the execution time difference:

time for i in {1..10000}; do [ "$STRING" != "foo" ]; done
time for i in {1..10000}; do [[ $STRING != foo ]]; done

Typical results show [[ is 2-3x faster due to being a shell builtin rather than an external command.

Where [[ really shines:

# Regex matching
if [[ $filename =~ ^[A-Za-z0-9_]+\.(txt|log)$ ]]; then
    echo "Valid filename"
fi

# Compound expressions
if [[ -d "$dir" && -w "$dir" ]]; then
    echo "Writable directory"
fi

# No quotes needed for right-hand glob
if [[ $file == *.config ]]; then
    echo "Config file detected"
fi
Single [ Double [[
POSIX-compliant scripts Bash-specific scripts
System init scripts Interactive shell scripts
Simple comparisons Complex pattern matching

Watch out for these mistakes:

# Wrong: Missing quotes in [ ]
[ $var = "value" ]  # Fails if $var contains spaces

# Wrong: Using -a/-o in [[ ]]
[[ $a -eq 1 -a $b -eq 2 ]]  # Should use && instead

# Wrong: Using =~ with quoted pattern
[[ $string =~ "pattern" ]]  # Quotes make it literal

In Bash scripting, both [ ] (single brackets) and [[ ]] (double brackets) are used for conditional testing, but they have significant differences in functionality and behavior.

The primary distinctions between these two constructs include:

  • [ ] is a built-in command (actually an alias for test)
  • [[ ]] is a Bash keyword with enhanced features
  • [[ ]] is generally safer and more powerful

Let's examine how each handles string comparison:

STRING="some value"

# Using single brackets
if [ "$STRING" != "foo" ]; then
    echo "Not equal (single brackets)"
fi

# Using double brackets
if [[ $STRING != foo ]]; then
    echo "Not equal (double brackets)"
fi

[[ ]] offers several improvements:

  • No need for quoting variables in most cases
  • Supports pattern matching with == and =~
  • Has logical operators && and || instead of -a and -o
  • Better handling of empty variables

Here's how pattern matching differs:

filename="document.txt"

# This won't work properly with single brackets
if [[ $filename == *.txt ]]; then
    echo "Text file detected"
fi

# Equivalent with single brackets requires extra quoting
if [ "$filename" = "*.txt" ]; then
    echo "This won't work as expected"
fi

Recommendations for usage:

  • Use [[ ]] for Bash scripts (when portability isn't required)
  • Use [ ] for POSIX-compliant scripts
  • Always prefer [[ ]] for complex conditions

Double brackets are generally faster as they don't require:

  • Word splitting
  • Filename expansion
  • External command invocation

Watch out for these issues:

# Problematic with single brackets
if [ $undefined_var = "value" ]; then
    echo "This may fail"
fi

# Safer with double brackets
if [[ $undefined_var = "value" ]]; then
    echo "This handles undefined variables"
fi

Double brackets support additional operators:

# Regular expression matching
if [[ "hello" =~ ^h ]]; then
    echo "Starts with h"
fi

# Numeric comparison without -lt/-gt
if (( 10 > 5 )); then
    echo "10 is greater than 5"
fi