[[ <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.
| 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):
( <EXPRESSION> )! <EXPRESSION><EXPRESSION1> && <EXPRESSION2><EXPRESSION1> || <EXPRESSION2>
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 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!
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.
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.
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.
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.
[[ ... ]] functionality isn't specified by POSIX(R), though it's a reserved word[[, 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.$(m='(abc(def))(\1)(\2)'; [[ abcdefabcdefdef =~ $m ]]; printf '<%s> ' $? "${BASH_REMATCH[@]}" )
will give <0> <abcdefabcdefdef> <abcdef> <def> <abcdef> <def>.=~ (regex) operator was introduced in Bash 3.0, and its behaviour changed in Bash 3.2: since 3.2, quoted strings and substrings are matched as literals by default.< and > operators (string collation order) has changed since Bash 4.0