Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Shell Script Dictionary
  3. test / [ ] / [[ ]]

test / [ ] / [[ ]]

Since: test / [ ] POSIX(sh互換)
[[ ]] Bash(bash拡張)

The test command in shell scripts is a built-in command that evaluates a condition and returns exit status 0 (true) or 1 (false). [ ] is an alias for test and behaves identically. In bash and zsh, the extended compound command [[ ]] is available. [[ ]] supports combining multiple conditions with && and ||, glob pattern matching with ==, and regular expression matching with =~. Use test / [ ] when POSIX compliance is required, and use [[ ]] in bash-specific scripts for safer, more readable code.

Equivalence of test and [ ]

test condition and [ condition ] are completely equivalent. [ is a shell built-in command that requires ] as its last argument. A space before ] is always required.

SyntaxDescription
test "$a" = "$b"Evaluates whether strings a and b are equal. POSIX-compliant.
[ "$a" = "$b" ]Completely equivalent to test. Spaces inside the brackets are required.
[ "$a" = "$b" ] ; echo $?Checks the exit status. Displays 0 for true and 1 for false.
# Confirm that test and [ ] behave identically

name="Tsunemori Akane"

# Using test
test "$name" = "Tsunemori Akane"
echo "test result: $?"    # 0 (true)

# Using [ ] (equivalent to test)
[ "$name" = "Tsunemori Akane" ]
echo "[ ] result: $?"     # 0 (true)

# Example that evaluates to false
[ "$name" = "Kogami Shinya" ]
echo "false result: $?"   # 1 (false)
$ bash test_same.sh
test result: 0
[ ] result: 0
false result: 1

bash Extensions with [[ ]]

[[ ]] is a compound command built into bash and zsh. Unlike [ ], it is processed by the shell as a keyword, so &&, ||, <, and > can be used directly inside it. Variables do not undergo word splitting even without quoting, making scripts safer to write.

FeatureSyntaxDescription
AND combination[[ condA && condB ]]True when both A and B are true. Can be written directly inside [[ ]].
OR combination[[ condA || condB ]]True when either A or B is true. Can be written directly inside [[ ]].
Glob pattern[[ "$str" == pattern* ]]Evaluates the right-hand side of == as a glob pattern. It is important not to quote the pattern.
Regex match[[ "$str" =~ regex ]]Evaluates using POSIX extended regular expressions. Matched portions are stored in the BASH_REMATCH array.
Lexicographic comparison[[ "$a" < "$b" ]]< and > can be used directly for lexicographic string comparison.
No word splitting[[ $var = "value" ]]$var is not subject to word splitting even without quoting (which is dangerous with [ ]).

Choosing Between [ ] and [[ ]]

Feature[ ] (test)[[ ]] (bash extension)
POSIX complianceCompliant. Works with sh and Alpine Linux.bash / zsh only. Cannot be used with #!/bin/sh.
AND / OR with multiple conditionsMust split into separate brackets: [ condA ] && [ condB ].Can be written inside a single [[ ]]: [[ condA && condB ]].
Glob pattern matchingNot available.Glob patterns can be used on the right-hand side of == (no quoting needed).
Regex matchingNot available.POSIX extended regular expressions are available via =~.
Variable quotingQuoting is always required to prevent word splitting on empty values.Works safely without quoting.
< / >Must be escaped as \< / \> to avoid being interpreted as redirections.Can be used directly as lexicographic string comparison operators.

Sample Code

psychopass_test_basic.sh
#!/bin/bash
# -----------------------------------------------
#  Demonstrates the equivalence of test and [ ]
#  using PSYCHO-PASS characters
# -----------------------------------------------

# -----------------------------------------------
#  Set character information into variables
# -----------------------------------------------

inspector="Tsunemori Akane"
enforcer="Kogami Shinya"
division=1
hue="clear"

echo "=== test and [ ] are completely equivalent ==="
echo ""

# String comparison using test
if test "$inspector" = "Tsunemori Akane"; then
    echo "[test] ${inspector} is an Inspector in Division 1."
fi

# Same condition written with [ ] (behaves identically)
if [ "$inspector" = "Tsunemori Akane" ]; then
    echo "[ ]   ${inspector} is an Inspector in Division 1."
fi

echo ""
echo "=== Check string length with -z / -n ==="
echo ""

# Check if a string is empty with -z
alias_name=""
if [ -z "$alias_name" ]; then
    echo "[test -z] alias_name is empty."
fi

# Check if a string is non-empty with -n
if [ -n "$enforcer" ]; then
    echo "[test -n] enforcer is set to \"${enforcer}\"."
fi

echo ""
echo "=== Numeric comparison ==="
echo ""

# Numeric equality comparison with -eq
if [ "$division" -eq 1 ]; then
    echo "Assigned to: Public Safety Bureau Criminal Investigation Division ${division}"
fi

# Numeric less-than comparison with -lt
crime_coefficient=40
threshold=100
if [ "$crime_coefficient" -lt "$threshold" ]; then
    echo "Crime coefficient ${crime_coefficient}: Clear. Not subject to enforcement."
fi
$ chmod +x psychopass_test_basic.sh
$ ./psychopass_test_basic.sh
=== test and [ ] are completely equivalent ===

[test] Tsunemori Akane is an Inspector in Division 1.
[ ]   Tsunemori Akane is an Inspector in Division 1.

=== Check string length with -z / -n ===

[test -z] alias_name is empty.
[test -n] enforcer is set to "Kogami Shinya".

=== Numeric comparison ===

Assigned to: Public Safety Bureau Criminal Investigation Division 1
Crime coefficient 40: Clear. Not subject to enforcement.
psychopass_double_bracket.sh
#!/bin/bash
# -----------------------------------------------
#  Demonstrates bash extensions of [[ ]]
#  using PSYCHO-PASS characters
#  (&&, ||, glob patterns, regex matching)
# -----------------------------------------------

# -----------------------------------------------
#  Set character information into an associative array
# -----------------------------------------------

declare -A role
role["Tsunemori Akane"]="Inspector"
role["Ginoza Nobuchika"]="Inspector"
role["Kogami Shinya"]="Enforcer"
role["Makishima Shogo"]="Latent Criminal"
role["Masaoka Tomomi"]="Enforcer"

echo "=== Combine multiple conditions in one [[ ]] with && ==="
echo ""

name="Kogami Shinya"
division=1

# With [ ], AND requires two separate brackets:
# [ "$role[$name]" = "Enforcer" ] && [ "$division" -eq 1 ]

# With [[ ]], && can be written inside a single bracket
if [[ "${role[$name]}" = "Enforcer" && "$division" -eq 1 ]]; then
    echo "${name} is an Enforcer in Division ${division}."
fi

echo ""
echo "=== Write OR conditions with || ==="
echo ""

target="Makishima Shogo"

# Check if the character is an Inspector or Enforcer
if [[ "${role[$target]}" = "Inspector" || "${role[$target]}" = "Enforcer" ]]; then
    echo "${target} is a member of the Public Safety Bureau."
else
    echo "${target} is not a member of the Public Safety Bureau. Role: ${role[$target]}"
fi

echo ""
echo "=== Glob pattern matching with == ==="
echo ""

# The right-hand side must not be quoted to be interpreted as a glob
for chara in "${!role[@]}"; do
    # Extract characters whose role ends with "er"
    if [[ "${role[$chara]}" == *er ]]; then
        echo "  [match] ${chara}: ${role[$chara]}"
    fi
done

echo ""
echo "=== Regex matching with =~ ==="
echo ""

# Sample data in "name:coefficient" format
data_list=(
    "Tsunemori Akane:40"
    "Ginoza Nobuchika:55"
    "Kogami Shinya:139"
    "Makishima Shogo:undefined"
    "Masaoka Tomomi:170"
)

# Extract entries with a numeric crime coefficient using a regex
echo "  Characters with a numeric crime coefficient:"
for entry in "${data_list[@]}"; do
    # Match using POSIX extended regex with =~
    # BASH_REMATCH[1] holds the first capture group
    if [[ "$entry" =~ ^([^:]+):([0-9]+)$ ]]; then
        chara_name="${BASH_REMATCH[1]}"
        coefficient="${BASH_REMATCH[2]}"
        echo "    ${chara_name}: crime coefficient ${coefficient}"
    fi
done
$ chmod +x psychopass_double_bracket.sh
$ ./psychopass_double_bracket.sh
=== Combine multiple conditions in one [[ ]] with && ===

Kogami Shinya is an Enforcer in Division 1.

=== Write OR conditions with || ===

Makishima Shogo is not a member of the Public Safety Bureau. Role: Latent Criminal

=== Glob pattern matching with == ===

  [match] Tsunemori Akane: Inspector
  [match] Ginoza Nobuchika: Inspector
  [match] Kogami Shinya: Enforcer
  [match] Masaoka Tomomi: Enforcer

=== Regex matching with =~ ===

  Characters with a numeric crime coefficient:
    Tsunemori Akane: crime coefficient 40
    Ginoza Nobuchika: crime coefficient 55
    Kogami Shinya: crime coefficient 139
    Masaoka Tomomi: crime coefficient 170
psychopass_comparison.sh
#!/bin/bash
# -----------------------------------------------
#  Compares the differences between [ ] and [[ ]]
#  using PSYCHO-PASS characters
# -----------------------------------------------

# -----------------------------------------------
#  Set up data for testing
# -----------------------------------------------

# List of character names
characters=("Tsunemori Akane" "Kogami Shinya" "Makishima Shogo" "Ginoza Nobuchika" "Masaoka Tomomi")

echo "=== Multiple conditions with [ ] (brackets must be separated) ==="
echo ""

name="Tsunemori Akane"
coefficient=40

# With [ ], AND requires connecting two brackets with && on the outside
if [ "$name" = "Tsunemori Akane" ] && [ "$coefficient" -lt 100 ]; then
    echo "[ ] AND: ${name} (coefficient ${coefficient}) is not subject to enforcement."
fi

echo ""
echo "=== Multiple conditions with [[ ]] (&& can be written inside the brackets) ==="
echo ""

# With [[ ]], && and || can be written inside a single bracket
if [[ "$name" = "Tsunemori Akane" && "$coefficient" -lt 100 ]]; then
    echo "[[ ]] AND: ${name} (coefficient ${coefficient}) is not subject to enforcement."
fi

echo ""
echo "=== Glob pattern: find names starting with 'Kog' ==="
echo ""

for chara in "${characters[@]}"; do
    # Glob pattern matching with == in [[ ]] (right-hand side is not quoted)
    if [[ "$chara" == Kog* ]]; then
        echo "  [glob match] ${chara}"
    fi
done

echo ""
echo "=== Regex: check if a name consists of two words ==="
echo ""

for chara in "${characters[@]}"; do
    # Check if the name has exactly two space-separated words
    if [[ "$chara" =~ ^[^ ]+\ [^ ]+$  ]]; then
        echo "  [2 words] ${chara}"
    else
        echo "  [other] ${chara}"
    fi
done

echo ""
echo "=== Lexicographic comparison: [ ] requires \<, [[ ]] allows < directly ==="
echo ""

a="Tsunemori Akane"
b="Kogami Shinya"

# With [ ], < must be escaped or it is interpreted as a redirect
if [ "$a" \< "$b" ]; then
    echo "[ ] lexicographic: \"${a}\" comes before \"${b}\"."
fi

# With [[ ]], < can be used directly
if [[ "$a" < "$b" ]]; then
    echo "[[ ]] lexicographic: \"${a}\" comes before \"${b}\"."
fi
$ chmod +x psychopass_comparison.sh
$ ./psychopass_comparison.sh
=== Multiple conditions with [ ] (brackets must be separated) ===

[ ] AND: Tsunemori Akane (coefficient 40) is not subject to enforcement.

=== Multiple conditions with [[ ]] (&& can be written inside the brackets) ===

[[ ]] AND: Tsunemori Akane (coefficient 40) is not subject to enforcement.

=== Glob pattern: find names starting with 'Kog' ===

  [glob match] Kogami Shinya

=== Regex: check if a name consists of two words ===

  [2 words] Tsunemori Akane
  [2 words] Kogami Shinya
  [2 words] Makishima Shogo
  [2 words] Ginoza Nobuchika
  [2 words] Masaoka Tomomi

=== Lexicographic comparison: [ ] requires \<, [[ ]] allows < directly ===

[ ] lexicographic: "Tsunemori Akane" comes before "Kogami Shinya".
[[ ]] lexicographic: "Tsunemori Akane" comes before "Kogami Shinya".

Using BASH_REMATCH

When a regex match with =~ succeeds, the match results are stored in the array variable BASH_REMATCH. BASH_REMATCH[0] holds the entire matched string, and BASH_REMATCH[1] onward correspond to capture groups (the portions enclosed in parentheses).

VariableContentsDescription
BASH_REMATCH[0]Entire matched stringContains the portion of the string matched by the whole regex.
BASH_REMATCH[1]First capture groupContains the portion matched by the first () in the regex.
BASH_REMATCH[2]Second capture groupContains the portion matched by the second () in the regex.
No matchArray is empty=~ returns false and nothing is stored in BASH_REMATCH.
#!/bin/bash
# -----------------------------------------------
#  Extract capture groups using BASH_REMATCH
# -----------------------------------------------

# Extract each part from a string in "name:crime_coefficient" format
record="Kogami Shinya:139"

# Define capture groups with ()
if [[ "$record" =~ ^([^:]+):([0-9]+)$ ]]; then
    echo "Full match:        ${BASH_REMATCH[0]}"    # Kogami Shinya:139
    echo "Name:              ${BASH_REMATCH[1]}"    # Kogami Shinya
    echo "Crime coefficient: ${BASH_REMATCH[2]}"    # 139
else
    echo "Format does not match."
fi
$ bash bash_rematch.sh
Full match:        Kogami Shinya:139
Name:              Kogami Shinya
Crime coefficient: 139

Notes on Glob Patterns

When using glob pattern matching with [[ "$var" == pattern ]], quoting the right-hand side pattern causes it to be treated as a string literal. To make the pattern function as a glob, it is important to leave the right-hand side unquoted.

SyntaxBehaviorDescription
[[ "$str" == *er ]]Glob pattern match*er is evaluated as a glob. Matches strings ending with "er".
[[ "$str" == "*er" ]]Exact string matchQuoting makes it an exact match against the literal string *er.
[[ "$str" == Kog* ]]Prefix matchMatches strings starting with "Kog".
[[ "$str" == *go ]]Suffix matchMatches strings ending with "go".
[[ "$str" == *ami* ]]Substring matchMatches strings containing "ami".

Summary

The test command and [ ] in shell scripts are completely equivalent and provide POSIX-compliant condition evaluation. Because they work in any shell including sh, use [ ] when portability is a priority. The bash/zsh-specific [[ ]] is processed as a compound command, so && and || can be used directly inside the brackets, and both glob pattern matching with == and regular expression matching with =~ are supported. Variables are not subject to word splitting, making scripts safer. In bash scripts, using [[ ]] as the default and switching to [ ] only when portability is needed is good practice. Regex match results are stored in the BASH_REMATCH array. For combining these constructs with if statements, see also if statement.

If you find any errors or copyright issues, please .