Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting | ||
---|---|---|
Prev | Chapter 8. Operations and Related Topics | Next |
In a script, operations execute in order of precedence: the higher precedence operations execute before the lower precedence ones. [1]
Table 8-1. Operator Precedence
Operator | Meaning | Comments |
---|---|---|
HIGHEST PRECEDENCE | ||
var++ var-- | post-increment, post-decrement | C-style operators |
++var --var | pre-increment, pre-decrement | |
! ~ | negation | logical / bitwise, inverts sense of following operator |
** | exponentiation | arithmetic operation |
* / % | multiplication, division, modulo | arithmetic operation |
+ - | addition, subtraction | arithmetic operation |
<< >> | left, right shift | bitwise |
-z -n | unary comparison | string is/is-not null |
-e -f -t -x, etc. | unary comparison | file-test |
< -lt > -gt <= -le >= -ge | compound comparison | string and integer |
-nt -ot -ef | compound comparison | file-test |
== -eq != -ne | equality / inequality | test operators, string and integer |
& | AND | bitwise |
^ | XOR | exclusive OR, bitwise |
| | OR | bitwise |
&& -a | AND | logical, compound comparison |
|| -o | OR | logical, compound comparison |
?: | trinary operator | C-style |
= | assignment | (do not confuse with equality test) |
*= /= %= += -= <<= >>= &= | combination assignment | times-equal, divide-equal, mod-equal, etc. |
, | comma | links a sequence of operations |
LOWEST PRECEDENCE |
In practice, all you really need to remember is the following:
The "My Dear Aunt Sally" mantra (multiply, divide, add, subtract) for the familiar arithmetic operations.
The compound logical operators, &&, ||, -a, and -o have low precedence.
The order of evaluation of equal-precedence operators is usually left-to-right.
Now, let's utilize our knowledge of operator precedence to analyze a couple of lines from the /etc/init.d/functions file, as found in the Fedora Core Linux distro.
1 while [ -n "$remaining" -a "$retry" -gt 0 ]; do 2 3 # This looks rather daunting at first glance. 4 5 6 # Separate the conditions: 7 while [ -n "$remaining" -a "$retry" -gt 0 ]; do 8 # --condition 1-- ^^ --condition 2- 9 10 # If variable "$remaining" is not zero length 11 #+ AND (-a) 12 #+ variable "$retry" is greater-than zero 13 #+ then 14 #+ the [ expresion-within-condition-brackets ] returns success (0) 15 #+ and the while-loop executes an iteration. 16 # ============================================================== 17 # Evaluate "condition 1" and "condition 2" ***before*** 18 #+ ANDing them. Why? Because the AND (-a) has a lower precedence 19 #+ than the -n and -gt operators, 20 #+ and therefore gets evaluated *last*. 21 22 ################################################################# 23 24 if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then 25 26 27 # Again, separate the conditions: 28 if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then 29 # --condition 1--------- ^^ --condition 2----- 30 31 # If file "/etc/sysconfig/i18n" exists 32 #+ AND (-a) 33 #+ variable $NOLOCALE is zero length 34 #+ then 35 #+ the [ test-expresion-within-condition-brackets ] returns success (0) 36 #+ and the commands following execute. 37 # 38 # As before, the AND (-a) gets evaluated *last* 39 #+ because it has the lowest precedence of the operators within 40 #+ the test brackets. 41 # ============================================================== 42 # Note: 43 # ${NOLOCALE:-} is a parameter expansion that seems redundant. 44 # But, if $NOLOCALE has not been declared, it gets set to *null*, 45 #+ in effect declaring it. 46 # This makes a difference in some contexts. |
To avoid confusion or error in a complex sequence of test operators, break up the sequence into bracketed sections.
|
[1] | Precedence, in this context, has approximately the same meaning as priority |