8.4. Operator Precedence

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

OperatorMeaningComments
 HIGHEST PRECEDENCE
var++ var--post-increment, post-decrementC-style operators
++var --varpre-increment, pre-decrement 
   
! ~negationlogical / bitwise, inverts sense of following operator
   
**exponentiationarithmetic operation
* / %multiplication, division, moduloarithmetic operation
+ -addition, subtractionarithmetic operation
   
<< >>left, right shiftbitwise
   
-z -nunary comparisonstring is/is-not null
-e -f -t -x, etc.unary comparisonfile-test
< -lt > -gt <= -le >= -gecompound comparisonstring and integer
-nt -ot -efcompound comparisonfile-test
== -eq != -neequality / inequalitytest operators, string and integer
   
&ANDbitwise
^XORexclusive OR, bitwise
|ORbitwise
   
&& -aANDlogical, compound comparison
|| -oORlogical, compound comparison
   
?:trinary operatorC-style
=assignment(do not confuse with equality test)
*= /= %= += -= <<= >>= &=combination assignmenttimes-equal, divide-equal, mod-equal, etc.
   
,commalinks a sequence of operations
 LOWEST PRECEDENCE

In practice, all you really need to remember is the following:

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.

Tip

To avoid confusion or error in a complex sequence of test operators, break up the sequence into bracketed sections.
   1 if [ "$v1" -gt "$v2"  -o  "$v1" -lt "$v2"  -a  -e "$filename" ]
   2 # Unclear what's going on here...
   3 
   4 if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]]
   5 # Much better -- the condition tests are grouped in logical sections.

Notes

[1]

Precedence, in this context, has approximately the same meaning as priority