Test operators cheat sheet
Every file, string, number and variable test for bash's [ ] and [[ ]], plus pattern and regex matching, with real output.
[ ] (also spelled test) is a POSIX command: quote every variable in it. [[ ]] is bash syntax:
no word splitting inside, &&/|| work, == matches globs and =~ regular expressions. A test
exits 0 for true, 1 for false and 2 for a malformed expression. Each row prints yes or no
so the result is visible.
Files
[[ -e notes.txt ]] && echo yes || echo no- The path exists (any type). False for a symlink whose target is missing.yes
[[ -f data/users.csv ]] && echo yes || echo no- Is a regular file (follows symlinks).yes
[[ -d data ]] && echo yes || echo no- Is a directory.yes
[[ -L link-to-notes ]] && echo yes || echo no- Is a symbolic link (
-his the same). Does not follow the link.yes [[ -r notes.txt ]] && echo yes || echo no- Is readable by you.
-wwritable,-xexecutable (or searchable for a directory).yes [[ -x scripts/greet.sh ]] && echo yes || echo no- Has execute permission for you.yes
touch empty; [[ -s empty ]] && echo yes || echo no- Exists and is larger than zero bytes.no
touch new; [[ new -nt notes.txt ]] && echo yes || echo no- First file is newer than the second (modification time).
-otis older.yes [[ notes.txt -ef link-to-notes ]] && echo yes || echo no- Both names refer to the same file (same device and inode).yes
[[ -p /dev/stdin ]]- Is a named pipe.
-Ssocket,-bblock device,-ccharacter device. [[ -t 1 ]]- File descriptor 1 is a terminal; use it to decide whether to print colors.
Strings
v=""; [[ -z $v ]] && echo yes || echo no- The string is empty.yes
v=x; [[ -n $v ]] && echo yes || echo no- The string is not empty.yes
[[ abc == abc ]] && echo yes || echo no- Strings are equal. In
[ ], the portable spelling is a single=.yes [[ abc != abd ]] && echo yes || echo no- Strings differ.yes
[[ apple < banana ]] && echo yes || echo no- Sorts before, in the current locale. In
[ ]write\<, or<becomes a redirection.yes [[ 10 < 9 ]] && echo yes || echo no<compares strings, so "10" sorts before "9". Use-ltor(( ))for numbers.yes
Patterns and regular expressions ([[ ]] only)
f=app.tar.gz; [[ $f == *.tar.gz ]] && echo yes || echo no- Glob pattern match when the right side is unquoted.yes
f=app.tar.gz; [[ $f == "*.tar.gz" ]] && echo yes || echo no- Quoting the right side compares literally.no
[[ v2.4.1 =~ ^v([0-9]+)\.([0-9]+) ]] && echo "major ${BASH_REMATCH[1]} minor ${BASH_REMATCH[2]}"- Extended regex match; capture groups land in BASH_REMATCH.major 2 minor 4
re="^[0-9]+$"; [[ 2026 =~ $re ]] && echo yes || echo no- Keep the regex in a variable and leave it unquoted, to avoid quoting surprises.yes
Integers
[[ 5 -eq 5 ]] && echo yes || echo no- Equal.
-nenot equal.yes [[ 3 -lt 10 ]] && echo yes || echo no- Less than.
-leless or equal.yes [[ 10 -gt 3 ]] && echo yes || echo no- Greater than.
-gegreater or equal.yes (( 10 > 3 )) && echo yes || echo no- The bash arithmetic form, with ordinary math symbols.yes
[ abc -gt 5 ]- A non-number in
[ ]is an error (status 2), not false./bin/bash: line 1: [: abc: integer expression expected
Variables and options
v=""; [[ -v v ]] && echo yes || echo no- The variable is set, even if empty (bash 4.2+). Pass the name, not
$v.yes unset v; [[ -v v ]] && echo yes || echo no- False for an unset variable.no
set -u; [[ -o nounset ]] && echo yes || echo no- A shell option is on (
set -olists the names).yes
Combining
[[ -f notes.txt && -s notes.txt ]] && echo yes || echo no- Logical AND inside
[[ ]].||is OR.yes [[ ! -d notes.txt ]] && echo yes || echo no- Negate a test.yes
f=a.csv; [[ -n $f && ( $f == *.csv || $f == *.tsv ) ]] && echo yes || echo no- Group with parentheses inside
[[ ]], no escaping needed.yes [ -f notes.txt ] && [ -r notes.txt ] && echo yes || echo no- Portable form for
[ ]andsh; avoid the obsolescent-aand-o.yes
From https://opscape.vip/cheatsheets/test-operators/ · checked 2026-10-31