Differences between revisions 5 and 7 (spanning 2 versions)
Revision 5 as of 2011-07-12 02:24:26
Size: 1690
Editor: pool-173-71-205-68
Comment: add missing "$"
Revision 7 as of 2013-07-26 22:20:03
Size: 2443
Comment: correction on &&/|| precedence.
Deletions are marked like this. Additions are marked like this.
Line 7: Line 7:
    if test A && test B || test C; then     if commandA && commandB || commandC; then
Line 9: Line 9:

    # or with test(1) calls:
    if [ testA ] && [ testB ] || [ testC ]; then
    ...
Line 11: Line 16:
The grouping is implicit in this case, because AND (`&&`) has a higher precedence than OR (`||`). If we need explicit grouping, then we can use curly braces: When they are shell operators between commands (as opposed to the `[[...]]` operators), `&&` and `||` have equal precedence, so processing is left to right.

If we need explicit grouping, then we can use curly braces:
Line 14: Line 21:
    # Bourne(?)
    if test A && { test B || test C; }; then
    # Bourne
    if commandA && { commandB || commandC; }; then
Line 21: Line 28:
[[BASH]] and KornShell have different, more powerful comparison commands with slightly different (easier) quoting: [[BASH]], zsh and the KornShell have different, more powerful comparison commands with slightly different (easier) quoting:
Line 27: Line 34:
    # Bash/ksh     # Bash/ksh/zsh
Line 35: Line 42:
    # Bash/ksh     # Bash/ksh/zsh
Line 40: Line 47:

Note that contrary to the `&&` and `||` ''shell'' operators, the `&&` operator in `((...))` and `[[...]]` has precedence over the `||` operator (same goes for `[`'s `-a` over `-o`), so for instance:

{{{
    [ a = a ] || [ b = c ] && [ c = d ]
}}}

is '''false''' because it's like:

{{{
    { [ a = a ] || [ b = c ]; } && [ c = d ]
}}}

(left to right association, no precedence), while

{{{
    [[ a = a || b = c && c = d ]]
}}}

is '''true''' because it's like:

{{{
    [[ a = a || ( b = c && c = d ) ]]
}}}

(`&&` has precedence over `||`).

How can I group expressions in an if statement, e.g. if (A AND B) OR C?

The portable (POSIX or Bourne) way is to use multiple test (or [) commands:

    # Bourne
    if commandA && commandB || commandC; then
    ...

    # or with test(1) calls:
    if [ testA ] && [ testB ] || [ testC ]; then
    ...

When they are shell operators between commands (as opposed to the [[...]] operators), && and || have equal precedence, so processing is left to right.

If we need explicit grouping, then we can use curly braces:

    # Bourne
    if commandA && { commandB || commandC; }; then
    ...

What we should not do is try to use the -a or -o operators of the test command, because the results are undefined.

BASH, zsh and the KornShell have different, more powerful comparison commands with slightly different (easier) quoting:

Examples:

    # Bash/ksh/zsh
    if (( (n>0 && n<10) || n == -1 ))
    then echo "0 < $n < 10, or n==-1"
    fi

or

    # Bash/ksh/zsh
    if [[ ( -f $localconfig && -f $globalconfig ) || -n $noconfig ]]
    then echo "configuration ok (or not used)"
    fi

Note that contrary to the && and || shell operators, the && operator in ((...)) and [[...]] has precedence over the || operator (same goes for ['s -a over -o), so for instance:

    [ a = a ] || [ b = c ] && [ c = d ]

is false because it's like:

    { [ a = a ] || [ b = c ]; } && [ c = d ]

(left to right association, no precedence), while

    [[ a = a || b = c && c = d ]]

is true because it's like:

    [[ a = a || ( b = c && c = d ) ]]

(&& has precedence over ||).

Note that the distinction between numeric and string comparisons is strict. Consider the following example:

    n=3
    if [[ $n>0 && $n<10 ]]
    then echo "$n is between 0 and 10"
    else echo "ERROR: invalid number: $n"
    fi

The output will be "ERROR: ....", because in a string comparision "3" is bigger than "10", because "3" already comes after "1", and the next character "0" is not considered. Changing the square brackets to double parentheses (( makes the example work as expected.


CategoryShell

BashFAQ/017 (last edited 2022-10-20 20:40:35 by emanuele6)