mirror of
https://github.com/flokoe/bash-hackers-wiki.git
synced 2024-11-01 23:03:05 +01:00
212 lines
9.1 KiB
Markdown
212 lines
9.1 KiB
Markdown
# The conditional expression
|
|
|
|
## Synopsis
|
|
|
|
[[ <EXPRESSION> ]]
|
|
|
|
## Description
|
|
|
|
The conditional expression is meant as the modern variant of the
|
|
[classic test command](../../commands/classictest.md). Since it is **not** a
|
|
normal command, Bash doesn't need to apply the normal commandline
|
|
parsing rules like recognizing `&&` as [command
|
|
list](../../syntax/basicgrammar.md#lists) operator.
|
|
|
|
The testing features basically are the same (see the lists for [classic
|
|
test command](../../commands/classictest.md)), 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](https://en.wikipedia.org/wiki/Regular_expression#POSIX_extended) `<ERE>` - `TRUE` on a match
|
|
|
|
See the [classic test operators](../../commands/classictest.md#file_tests) Do **not** use the `test`-typical operators `-a` and `-o` for AND and OR.
|
|
|
|
See also [arithmetic comparisons](../../syntax/arith_expr.md#comparisons) Using `(( <EXPRESSION> ))`, the [arithmetic expression compound command](../../syntax/ccmd/arithmetic_eval.md)
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
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](../../syntax/pattern.md). 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
|
|
|
|
[Word splitting](../../syntax/expansion/wordsplit.md) and [pathname
|
|
expansion](../../syntax/expansion/globs.md) 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](../../commands/classictest.md), 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 [shell_options](../../internals/shell_options.md).
|
|
|
|
#### 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](../../syntax/shellvars.md#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
|
|
|
|
- `[[ ... ]]` 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. This requires Bash to be linked against
|
|
glibc, so it won't necessarily work on all platforms. For example,
|
|
`$(m='(abc(def))(\1)(\2)'; [[ abcdefabcdefdef =~ $m ]]; printf '<%s> ' $? "${BASH_REMATCH[@]}" )`
|
|
will give `<0> <abcdefabcdefdef> <abcdef> <def> <abcdef> <def>`.
|
|
- the `=~` (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.
|
|
- the behaviour of the `<` and `>` operators (string collation order)
|
|
has changed since Bash 4.0
|
|
|
|
## See also
|
|
|
|
- Internal: [pattern matching language](../../syntax/pattern.md)
|
|
- Internal: [the classic test command](../../commands/classictest.md)
|
|
- Internal: [the if-clause](../../syntax/ccmd/if_clause.md)
|
|
- [What is the difference between test, \[ and \[\[
|
|
?](http://mywiki.wooledge.org/BashFAQ/031) - BashFAQ 31 - Greg's
|
|
wiki.
|