This is an old revision of the document!

The conditional expression




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.

( <EXPRESSION> )Used to group expressions, to influence precedence of operators
<STRING> == <PATTERN><STRING> is checked against the pattern <PATTERN> - TRUE on a match
<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

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.

:V4: 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):

  • ( <EXPRESSION> )

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...!"
  echo "Sorry, no match :-("

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...!"
  echo "Sorry, no match :-("

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.

A good practise is to put the regular expression to match against into an own variable:


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

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

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

Behaviour differences compared to the builtin test command

:V4: 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 both behave differently:

$ ./
[[ ' 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.


Portability considerations

  • [[ ... ]] functionality isn't specified by POSIX(R), though it's a reserved word
  • Amongst the major "POSIX-shell superset languages" (for lack of a better term) which do have [[, the test expression compound command is one of the very most portable non-POSIX features. Aside from the =~ operator, almost every major feature is consistent between Ksh88, Ksh93, mksh, Zsh, and Bash. Ksh93 also adds a large number of unique pattern matching features not supported by other shells including support for several different regex dialects, which are invoked using a different syntax from Bash's =~, though =~is still supported by ksh and defaults to ERE.
  • As an extension to POSIX ERE, most GNU software supports backreferences in ERE, including Bash. According to POSIX, only BRE is supposed to support them.

$ m='(abc)\1'; [[ abcabc =~ $m ]]; printf '%s\n' $? "${BASH_REMATCH[@]}"

  • the behaviour of the =~ (regex) operator has changed between Bash 3.0 and Bash 3.2
  • the behaviour of the < and > operators (string collation order) has changed since Bash 4.0

See also


Enter your comment. Wiki syntax is allowed: