Table of Contents

The conditional expression

Synopsis

[[ <EXPRESSION> ]]

Description

The conditional expression is meant as the modern variant of the classic test command. Since it is not a normal command, Bash doesn't need to apply the normal commandline parsing rules like recognizing && as command list operator.

The testing features basically are the same (see the lists for classic test command), with some additions and extensions.

Operator Description
( <EXPRESSION> ) Used to group expressions, to influence precedence of operators
<EXPRESSION1> && <EXPRESSION2> TRUE if <EXPRESSION1>and<EXPRESSION2> are TRUE (do not use -a!)
<EXPRESSION1> || <EXPRESSION2> TRUE if <EXPRESSION1>or<EXPRESSION2> is TRUE (do not use -o!)
<STRING> == <PATTERN> <STRING> is checked against the pattern <PATTERN> - TRUE on a match
But note¹, quoting the pattern forces a literal comparison.
<STRING> = <PATTERN> equivalent to the == operator
<STRING> != <PATTERN> <STRING> is checked against the pattern <PATTERN> - TRUE on no match
<STRING> =~ <ERE> <STRING> is checked against the extended regular expression <ERE> - TRUE on a match
See the classic test operators Do not use the test-typical operators -a and -o for AND and OR.
See also arithmetic comparisons Using (( <EXPRESSION> )), the arithmetic expression compound command

When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules of Pattern Matching. If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters.

¹Any part of the pattern may be quoted to force it to be matched as a literal string.

When the operators < and > are used (string collation order), the test happens using the current locale when the compat level is greater than "40".

Operator precedence (highest ⇒ lowest):

Do not use the test-typical operators -a and -o for AND and OR, they are not known to the conditional expression. Instead, use the operators && and ||.

Word splitting

Word splitting and pathname expansion are not performed in the expression you give. That means, a variable containing spaces can be used without quoting:

sentence="Be liberal in what you accept, and conservative in what you send"
checkme="Be liberal in what you accept, and conservative in what you send"
if [[ $sentence == $checkme ]]; then
  echo "Matched...!"
else
  echo "Sorry, no match :-("
fi

Compare that to the classic test command, where word splitting is done (because it's a normal command, not something special):

sentence="Be liberal in what you accept, and conservative in what you send"
checkme="Be liberal in what you accept, and conservative in what you send"
if [ "$sentence" == "$checkme" ]; then
  echo "Matched...!"
else
  echo "Sorry, no match :-("
fi

You need to quote that variable reference in the classic test command, since (due to the spaces) the word splitting will break it otherwise!

Regular Expression Matching

Using the operator =~, the left hand side operand is matched against the extended regular expression (ERE) on the right hand side.

This is consistent with matching against patterns: Every quoted part of the regular expression is taken literally, even if it contains regular expression special characters.

Best practise is to put the regular expression to match against into a variable. This is to avoid shell parsing errors on otherwise valid regular expressions.

REGEX="^[[:upper:]]{2}[[:lower:]]*$"

# Test 1
STRING=Hello
if [[ $STRING =~ $REGEX ]]; then
  echo "Match."
else
  echo "No match."
fi
# ==> "No match."

# Test 2
STRING=HEllo
if [[ $STRING =~ $REGEX ]]; then
  echo "Match."
else
  echo "No match."
fi
# ==> "Match."

The interpretation of quoted regular expression special characters can be influenced by setting the compat31 and compat32 shell options (compat* in general). See List of shell options.

The special BASH_REMATCH array variable

An array variable whose members are assigned by the =~ binary operator to the [[ conditional command.

The element with index 0 is the portion of the string matching the entire regular expression. The element with index n is the portion of the string matching the nth parenthesized subexpression.

See BASH_REMATCH.

Example:

if [[ "The quick, red fox" =~ ^The\ (.*),\ (.*)\ fox$ ]]; then
    echo "${BASH_REMATCH[0]} is ${BASH_REMATCH[1]} and ${BASH_REMATCH[2]}.";
fi

==> The quick, red fox is quick and red.

Behaviour differences compared to the builtin test command

As of Bash 4.1 alpha, the test primaries '<' and '>' (compare strings lexicographically) use the current locale settings, while the same primitives for the builtin test command don't. This leads to the following situation where they behave differently:

$ ./cond.sh
[[ ' 4' < '1' ]]        --> exit 1
[[ 'step+' < 'step-' ]] --> exit 1
[ ' 4' \< '1' ]         --> exit 0
[ 'step+' \< 'step-' ]  --> exit 0

It won't be aligned. The conditional expression continues to respect the locate, as introduced with 4.1-alpha, the builtin test/[ command continues to behave differently.

Implicit arithmetic context

When you use a numeric comparison, the arguments are evaluated as an arithmetic expression. The arithmetic expression must be quoted if it both contains whitespace and is not the result of an expansion.

[[ 'i=5, i+=2' -eq 3+4 ]] && echo true # prints true.

Examples

Portability considerations

See also