Bash Test Operators Reference

All [ ] and [[ ]] test operators by type — file, string, arithmetic, regex.

Searchable Bash test operator reference covering file-attribute tests (-f, -d, -nt), string emptiness (-z, -n), numeric comparison (-eq, -lt), regex matching (=~) and logical combinators, each with a working example. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What is the difference between [ ] and [[ ]]?

[ ] is the POSIX test command and treats its operands as separate words, so unquoted variables can break it. [[ ]] is a Bash keyword that parses the whole expression, supports && and || and the =~ regex operator, and does not word-split unquoted variables.

Bash test operators

Bash conditional expressions decide which branch of an if, while or && chain runs. They live inside the test command, its [ ] alias, or the more capable [[ ]] keyword. The operators fall into clear families: file-attribute tests, string emptiness checks, string and numeric comparisons, regex matching, and logical combinators. This page is a searchable, offline reference with a working example for every operator.

How it works

A test operator evaluates to a true (exit status 0) or false (non-zero) result, which the surrounding control structure uses:

  • File tests are unary operators like -f (regular file), -d (directory) and -x (executable) that inspect a path, plus binary comparisons -nt, -ot and -ef that compare two files by timestamp or inode.
  • String tests -z and -n check for an empty or non-empty value.
  • Comparison uses =/==/!= for strings and -eq, -ne, -lt, -le, -gt, -ge for integers — never mix the two.
  • Regex uses [[ s =~ re ]], available only in double brackets, storing captures in BASH_REMATCH.
  • Logical operators negate (!) or combine (&&, ||, or the legacy -a, -o).

The most important rule: prefer [[ ]] for new scripts. It avoids word-splitting surprises, supports glob and regex matching, and lets you use &&/|| inside a single test.

Tips and examples

Always quote variables in [ ] to avoid syntax errors when a value is empty or contains spaces:

if [ -z "$name" ]; then
  echo "name is empty"
fi

Combine conditions cleanly inside double brackets:

if [[ -f "$config" && -r "$config" ]]; then
  source "$config"
fi

Capture parts of a match with a regex:

if [[ "$ver" =~ ^([0-9]+)\.([0-9]+)$ ]]; then
  major=${BASH_REMATCH[1]}
  minor=${BASH_REMATCH[2]}
fi

Remember the numeric-versus-string distinction: use -eq family operators for integers and =/!= for text, or comparisons will silently give the wrong answer.

Edge cases and common mistakes

Empty-variable pitfalls. Inside [ ], an unquoted empty variable becomes nothing at all, turning [ $x = "hello" ] into [ = "hello" ], which is a parse error. Always quote: [ "$x" = "hello" ]. Inside [[ ]] this is not an issue because the keyword does not word-split.

Combining conditions in [ ]. The -a and -o operators ([ a -a b ]) are POSIX but deprecated because they are ambiguous when an operand looks like an operator. Use two separate tests joined by && or || at the shell level instead, or switch to [[ ]].

-e versus -f. -e is true for any existing path — file, directory, symlink, or device. -f is true only for regular files. A common mistake is using -f to test whether something exists and then being surprised when a directory returns false.

String comparison versus pattern matching. Inside [[ ]], the == and != operators support glob patterns on the right-hand side ([[ $file == *.log ]]), which is different from the =~ regex operator. Do not quote the pattern or it is treated as a literal string.

Operator quick-reference

FamilyOperatorsWorks in
File existence-e, -f, -d, -L, -s[ ] and [[ ]]
File permissions-r, -w, -x[ ] and [[ ]]
File comparison-nt, -ot, -ef[ ] and [[ ]]
String empty/non-empty-z, -n[ ] and [[ ]]
String comparison=, ==, !=, <, >[ ] (some) / [[ ]]
Regex match=~[[ ]] only
Integer comparison-eq, -ne, -lt, -le, -gt, -ge[ ] and [[ ]]
Logical!, -a, -o, &&, ||mixed — use &&/|| in [[ ]]