XXX 8.1. Operators

** assignment**

`` variable assignment ``
Initializing or changing the value of a variable
=

All-purpose assignment operator, which works for both arithmetic and string assignments.

var=27
category=minerals  # No spaces allowed after the "=".

Compte

Do not confuse the “=” assignment operator with the = test operator .


#   =  as a test ope

rator

if [ “$string1” = “$
string2” ]
then
command

fi

# if [ “X$string1”

= “X$string2” ] is safer ,

#+ to prevent an err
or message should one of
the variables be empty.
# (The prepended “X

” characters cancel out. )


#   =  as a test operator

if [ "$string1" = "$string2" ]
then
   command
fi

#  if [ "X$string1" = "X$string2" ] is safer,
#+ to prevent an error message should one of the variables be empty.
#  (The prepended "X" characters cancel out.)
#   =  as a test operator

if [ "$string1" = "$string2" ]
then
   command
fi

#  if [ "X$string1" = "X$string2" ] is safer,
#+ to prevent an error message should one of the variables be empty.
#  (The prepended "X" characters cancel out.)

** arithmetic operators**

  • plus
  • minus
*
multiplication
/
division
**

exponentiation

# Bash, version 2.02, introduced the "**" exponentiation operator.

let "z=5**3"    # 5 * 5 * 5
echo "z = $z"   # z = 125
%

modulo, or mod (returns the remainder of an integer division operation)

bash$ expr 5 % 3
2

5/3 = 1, with remainder 2

This operator finds use in, among other things, generating numbers within a specific range (see Example 9-11 and Example 9-15 ) and formatting program output (see Example 27-16 and Example A-6 ). It can even be used to generate prime numbers, (see Example A-15 ). Modulo turns up surprisingly often in numerical recipes.

Exemple 1. Greatest common divisor

#!/bin/bash
# gcd.sh: greatest common divisor
#         Uses Euclid's algorithm

#  The "greatest common divisor" (gcd) of two integers
#+ is the largest integer that will divide both, leaving no remainder.

#  Euclid's algorithm uses successive division.
#    In each pass,
#+      dividend <---  divisor
#+      divisor  <---  remainder
#+   until remainder = 0.
#    The gcd = dividend, on the final pass.
#
#  For an excellent discussion of Euclid's algorithm, see
#+ Jim Loy's site, http://www.jimloy.com/number/euclids.htm.


# ------------------------------------------------------
# Argument check
ARGS=2
E_BADARGS=85

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` first-number second-number"
  exit $E_BADARGS
fi
# ------------------------------------------------------


gcd ()
{

  dividend=$1             #  Arbitrary assignment.
  divisor=$2              #! It doesn't matter which of the two is larger.
                          #  Why not?

  remainder=1             #  If an uninitialized variable is used inside
                          #+ test brackets, an error message results.

  until [ "$remainder" -eq 0 ]
  do    #  ^^^^^^^^^^  Must be previously initialized!
    let "remainder = $dividend % $divisor"
    dividend=$divisor     # Now repeat with 2 smallest numbers.
    divisor=$remainder
  done                    # Euclid's algorithm

}                         # Last $dividend is the gcd.


gcd $1 $2

echo; echo "GCD of $1 and $2 = $dividend"; echo


# Exercises :
# ---------
# 1) Check command-line arguments to make sure they are integers,
#+   and exit the script with an appropriate error message if not.
# 2) Rewrite the gcd () function to use local variables.

exit 0
+=
plus-equal (increment variable by a constant) ` [1]
<ops.html#FTN.AEN3907>`__

`` let “var += 5” `` results in `` var `` being incremented by `` 5 `` .

-=
minus-equal (decrement variable by a constant)
*=

times-equal (multiply variable by a constant)

`` let “var *= 4” `` results in `` var `` being multiplied by `` 4 `` .

/=
slash-equal (divide variable by a constant)
%=

mod-equal ( remainder of dividing variable by a constant)

Arithmetic operators often occur in an `expr <moreadv.html#EXPRREF>`__ or `let <internal.html#LETREF>`__ expression.

Exemple 2. Ús dels operadors aritmètics

#!/bin/bash
# Counting to 11 in 10 different ways.

n=1; echo -n "$n "

let "n = $n + 1"   # let "n = n + 1"  also works.
echo -n "$n "


: $((n = $n + 1))
#  ":" necessary because otherwise Bash attempts
#+ to interpret "$((n = $n + 1))" as a command.
echo -n "$n "

(( n = n + 1 ))
#  A simpler alternative to the method above.
#  Thanks, David Lombard, for pointing this out.
echo -n "$n "

n=$(($n + 1))
echo -n "$n "

: $[ n = $n + 1 ]
#  ":" necessary because otherwise Bash attempts
#+ to interpret "$[ n = $n + 1 ]" as a command.
#  Works even if "n" was initialized as a string.
echo -n "$n "

n=$[ $n + 1 ]
#  Works even if "n" was initialized as a string.
#* Avoid this type of construct, since it is obsolete and nonportable.
#  Thanks, Stephane Chazelas.
echo -n "$n "

# Now for C-style increment operators.
# Thanks, Frank Wang, for pointing this out.

let "n++"          # let "++n"  also works.
echo -n "$n "

(( n++ ))          # (( ++n ))  also works.
echo -n "$n "

: $(( n++ ))       # : $(( ++n )) also works.
echo -n "$n "

: $[ n++ ]         # : $[ ++n ] also works
echo -n "$n "

echo

exit 0

|Note

Integer variables in older versions of Bash were signed long (32-bit) integers, in the range of -2147483648 to 2147483647. An operation that took a variable outside these limits gave an erroneous result.


   echo $BASH_VERSION
# 1.14

   a=2147483646
   echo "a = $a"
# a = 2147483646
   let "a+=1"
# Increment "a".
   echo "a = $a"
# a = 2147483647
   let "a+=1"
# increment "a" again,
past the limit.
echo “a = $a”

# a = -2147483648

# ERROR: out of ra

nge,

# + and the leftmost bit, the sign bit,

# + has been set, ma

king the result negative .


As of version >= 2.05b, Bash supports 64-bit integers.

echo $BASH_VERSION   # 1.14

a=2147483646
echo "a = $a"        # a = 2147483646
let "a+=1"           # Increment "a".
echo "a = $a"        # a = 2147483647
let "a+=1"           # increment "a" again, past the limit.
echo "a = $a"        # a = -2147483648
                     #      ERROR: out of range,
                     # +    and the leftmost bit, the sign bit,
                     # +    has been set, making the result negative.
echo $BASH_VERSION   # 1.14

a=2147483646
echo "a = $a"        # a = 2147483646
let "a+=1"           # Increment "a".
echo "a = $a"        # a = 2147483647
let "a+=1"           # increment "a" again, past the limit.
echo "a = $a"        # a = -2147483648
                     #      ERROR: out of range,
                     # +    and the leftmost bit, the sign bit,
                     # +    has been set, making the result negative.

Compte

Bash does not understand floating point arithmetic. It treats numbers containing a decimal point as strings.


a=1.5

let "b = $a + 1.3"
# Error.
# t2.sh: let: b = 1.
5 + 1.3: syntax error in
expression
#
(error token is

”.5 + 1.3”)

echo “b = $b”

# b=1


Use bc in scripts that that need floating point calculations or math library functions.

a=1.5

let "b = $a + 1.3"  # Error.
# t2.sh: let: b = 1.5 + 1.3: syntax error in expression
#                            (error token is ".5 + 1.3")

echo "b = $b"       # b=1
a=1.5

let "b = $a + 1.3"  # Error.
# t2.sh: let: b = 1.5 + 1.3: syntax error in expression
#                            (error token is ".5 + 1.3")

echo "b = $b"       # b=1

bitwise operators. The bitwise operators seldom make an appearance in shell scripts. Their chief use seems to be manipulating and testing values read from ports or sockets . “Bit flipping” is more relevant to compiled languages, such as C and C++, which provide direct access to system hardware. However, see vladz’s ingenious use of bitwise operators in his base64.sh ( Example A-54 ) script.

** bitwise operators**

<<
bitwise left shift (multiplies by `` 2 `` for each shift position)
<<=

left-shift-equal

`` let “var <<= 2” `` results in `` var `` left-shifted `` 2 `` bits (multiplied by `` 4 `` )

>>
bitwise right shift (divides by `` 2 `` for each shift position)
>>=
right-shift-equal (inverse of <<= )
&
bitwise AND
&=
bitwise AND-equal
bitwise OR
|=
bitwise OR-equal
~
bitwise NOT
^
bitwise XOR
^=
bitwise XOR-equal

** logical (boolean) operators**

!

NOT

if [ ! -f $FILENAME ]
then
  ...
&&

AND

if [ $condition1 ] && [ $condition2 ]
#  Same as:  if [ $condition1 -a $condition2 ]
#  Returns true if both condition1 and condition2 hold true...

if [[ $condition1 && $condition2 ]]    # Also works.
#  Note that && operator not permitted inside brackets
#+ of [ ... ] construct.

Nota

&& may also be used, depending on context, in an `and

list <list-cons.html#LISTCONSREF>`__ to concatenate commands.

|

OR

if [ $condition1 ] |[ $condition2 ]
# Same as:  if [ $condition1 -o $condition2 ]
# Returns true if either condition1 or condition2 holds true...

if [[ $condition1 |$condition2 ]]    # Also works.
#  Note that |operator not permitted inside brackets
#+ of a [ ... ] construct.

Nota

Bash tests the exit status of each statement linked with a logical operator.

Exemple 3. Compound Condition Tests Using && and |

#!/bin/bash

a=24
b=47

if [ "$a" -eq 24 ] && [ "$b" -eq 47 ]
then
  echo "Test #1 succeeds."
else
  echo "Test #1 fails."
fi

# ERROR:   if [ "$a" -eq 24 && "$b" -eq 47 ]
#+         attempts to execute  ' [ "$a" -eq 24 '
#+         and fails to finding matching ']'.
#
#  Note:  if [[ $a -eq 24 && $b -eq 24 ]]  works.
#  The double-bracket if-test is more flexible
#+ than the single-bracket version.
#    (The "&&" has a different meaning in line 17 than in line 6.)
#    Thanks, Stephane Chazelas, for pointing this out.


if [ "$a" -eq 98 ] |[ "$b" -eq 47 ]
then
  echo "Test #2 succeeds."
else
  echo "Test #2 fails."
fi


#  The -a and -o options provide
#+ an alternative compound condition test.
#  Thanks to Patrick Callahan for pointing this out.


if [ "$a" -eq 24 -a "$b" -eq 47 ]
then
  echo "Test #3 succeeds."
else
  echo "Test #3 fails."
fi


if [ "$a" -eq 98 -o "$b" -eq 47 ]
then
  echo "Test #4 succeeds."
else
  echo "Test #4 fails."
fi


a=rhino
b=crocodile
if [ "$a" = rhino ] && [ "$b" = crocodile ]
then
  echo "Test #5 succeeds."
else
  echo "Test #5 fails."
fi

exit 0

The && and |operators also find use in an arithmetic context.

bash$ echo $(( 1 && 2 )) $((3 && 0)) $((4 |0)) $((0 || 0))
1 0 1 0

** miscellaneous operators**

,

Comma operator

The comma operator chains together two or more arithmetic operations. All the operations are evaluated (with possible side effects . ` [2] <ops.html#FTN.AEN4242>`__

let "t1 = ((5 + 3, 7 - 1, 15 - 4))"
echo "t1 = $t1"           ^^^^^^  # t1 = 11
# Here t1 is set to the result of the last operation. Why?

let "t2 = ((a = 9, 15 / 3))"      # Set "a" and calculate "t2".
echo "t2 = $t2    a = $a"         # t2 = 5    a = 9

The comma operator finds use mainly in for loops . See Example 11-13 .

Notes

` [1] <ops.html#AEN3907>`__

In a different context, += can serve as a string concatenation operator. This can be useful for modifying *environmental variables* .

` [2] <ops.html#AEN4242>`__

Side effects are, of course, unintended – and usually undesirable – consequences.