Operator Precedence

Bash Unix Shell Scripting:
Chapter 8. Operations and Related Topics

Operator Precedence

In a script, operations execute in order of precedence: the higher precedence operations execute before the lower precedence ones.

Table 8-1. Operator Precedence

Operator Meaning Comments
  HIGHEST PRECEDENCE
var++ var-- post-increment, post-decrement operators
++var --var pre-increment, pre-decrement  
     
! ~ logical / bitwise, inverts sense of following operator
     
**
* / % multiplication, division, modulo arithmetic operation
+ - addition, subtraction arithmetic operation
     
<< >> left, right shift
     
-z -n unary comparison string is/is-not
-e -f -t -x, etc. unary comparison
< -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 , compound comparison
|| -o OR logical, compound comparison
     
?: C-style
= (do not confuse with equality test)
*= /= %= += -= <<= >>= &= times-equal, divide-equal, mod-equal, etc.
     
, links 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.

while [ -n "$remaining" -a "$retry" -gt 0 ]; do
# This looks rather daunting at first glance.
# Separate the conditions:
while [ -n "$remaining" -a "$retry" -gt 0 ]; do
#       --condition 1-- ^^ --condition 2-
#  If variable "$remaining" is not zero length
#+      AND (-a)
#+ variable "$retry" is greater-than zero
#+ then
#+ the [ expresion-within-condition-brackets ] returns success (0)
#+ and the while-loop executes an iteration.
#  ==============================================================
#  Evaluate "condition 1" and "condition 2" ***before***
#+ ANDing them. Why? Because the AND (-a) has a lower precedence
#+ than the -n and -gt operators,
#+ and therefore gets evaluated *last*.
#################################################################
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
# Again, separate the conditions:
if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
#    --condition 1--------- ^^ --condition 2-----
#  If file "/etc/sysconfig/i18n" exists
#+      AND (-a)
#+ variable $NOLOCALE is zero length
#+ then
#+ the [ test-expresion-within-condition-brackets ] returns success (0)
#+ and the commands following execute.
#
#  As before, the AND (-a) gets evaluated *last*
#+ because it has the lowest precedence of the operators within
#+ the test brackets.
#  ==============================================================
#  Note:
#  ${NOLOCALE:-} is a parameter expansion that seems redundant.
#  But, if $NOLOCALE has not been declared, it gets set to *null*,
#+ in effect declaring it.
#  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.

if [ "$v1" -gt "$v2"  -o  "$v1" -lt "$v2"  -a  -e "$filename" ]
# Unclear what's going on here...
if [[ "$v1" -gt "$v2" ]] || [[ "$v1" -lt "$v2" ]] && [[ -e "$filename" ]]
# Much better -- the condition tests are grouped in logical sections.

Notes

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