[ ] vs [[ ]] in Bash: Single vs Double Brackets
Understand the difference between [ ] (test) and [[ ]] in bash. Learn when to use each, POSIX compatibility, and common mistakes with == vs =.
Detailed Explanation
Single Brackets [ ] vs Double Brackets [[ ]]
The choice between [ ] and [[ ]] is one of the most confusing
aspects of shell scripting. They look similar but behave quite differently.
[ ] — The test Command
[ ] is actually the test command. It is a regular command, not
shell syntax:
# These are equivalent:
[ "$var" = "hello" ]
test "$var" = "hello"
Rules for [ ]:
- Variables MUST be quoted:
[ "$var" = "value" ] - Use
=for string comparison (not==) - Use
-eq,-lt,-gtfor numeric comparison - No pattern matching or regex
&&and||must be outside:[ cond1 ] && [ cond2 ]
[[ ]] — Bash Keyword
[[ ]] is a Bash/Zsh/Ksh built-in keyword with additional features:
# No word splitting — quoting optional (but still recommended)
[[ $var = "hello" ]]
# Pattern matching with ==
[[ $file == *.txt ]]
# Regex matching with =~
[[ $email =~ ^[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]+$ ]]
# Logical operators inside
[[ $a -gt 0 && $b -lt 100 ]]
Common Mistake: == in [ ]
# WRONG: == is not POSIX in [ ]
if [ "$var" == "value" ]; then # Works in bash but not sh
# CORRECT for [ ]:
if [ "$var" = "value" ]; then
# CORRECT for [[ ]]:
if [[ "$var" == "value" ]]; then
Comparison Table
| Feature | [ ] |
[[ ]] |
|---|---|---|
| POSIX compatible | Yes | No (bash/zsh/ksh) |
| Word splitting | Yes (must quote) | No |
| Pattern matching | No | == *.txt |
| Regex | No | =~ regex |
| Logical operators | External &&/` |
|
| String comparison | = |
= or == |
Recommendation
- Use
[[ ]]in Bash scripts (with#!/bin/bashshebang) - Use
[ ]only when POSIX compatibility is required (#!/bin/sh) - Always quote variables in
[ ]to prevent word splitting
Use Case
Writing conditional logic in shell scripts, validating user input, checking file existence and types, and pattern matching on strings. Understanding the difference is essential for anyone writing shell scripts that need to be portable or that use advanced matching.
Try It — Shell Script Linter
Related Topics
SC2148: Missing Shebang Line in Shell Scripts
Script Setup
Writing POSIX-Compatible Shell Scripts
POSIX Compatibility
SC2086: Unquoted Variable Expansion in Shell Scripts
Quoting
SC2006: Replace Backtick Command Substitution with $()
Deprecated Syntax
Bash Strict Mode: set -euo pipefail Explained
Script Setup