All-purpose assignment operator, which works for both arithmetic and string assignments.
var=27 category=minerals # No spaces allowed after the "=".
Caution: Do not confuse the =
assignment operator with the
=
test operator.
# = 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.)
Exponentation
# 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 (TODO see Example 9-11 and Example 9-15) and formatting program output (TODO see Example 27-16 and Example A-6). It can even be used to generate prime numbers, (TODO see Example A-15). Modulo turns up surprisingly often in numerical recipes.
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]
let "var += 5"
Results in var being incremented by 5.
Times-equal (multiply variable by a constant)
let "var *= 4"
Results in var being multiplied by 4.
Mod-equal (remainder of dividing variable by a constant)
Arithmetic operators often occur in an expr
or let
expression.
Using Arithmetic Operations
#!/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.
Example:
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.
As of version >= 2.05b, Bash supports 64-bit integers.
Caution: Bash does not understand floating point arithmetic. It treats numbers containing a decimal point as strings.
Example:
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.
left-shift-equal
let "var <<= 2"
Results in var left-shifted 2 bits (multiplied by 4)
<<=
)<<=
)
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.
Note: &&
may also be used, depending on context, in an and list
to concatenate (TODO: ref) 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.
Note: Bash tests the exit status of each statement linked with a logical operator.
#!/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
Comma operator
The comma operator chains together two or more arithmetic operations. All the operations are evaluated (with possible side effects). [2]
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 (TODO)