Arithmetic!

It all adds up.

Introduction

Depending on what type of work you want your scripts to do you may end up using arithmetic a lot or not much at all. It's a reasonable certainty however that you will need to use arithmetic at some point. Like variables, they are reasonably easy to implement and knowing how to do so is an essential skill in Bash scripting mastery.

There are several ways to go about arithmetic in Bash scripting. We'll cover them for completeness but the recommended approach is arithmetic expansion (covered last).

Let

let is a builtin function of Bash that allows us to do simple arithmetic. It follows the basic format:

let <arithmetic expression>

The arithmetic expression can take a variety of formats which we'll outline below. The first part is generally always a variable which the result is saved into however.

Let's look at a simple example:

let_example.sh

  1. #!/bin/bash
  2. # Basic arithmetic using let
  3. let a=5+4
  4. echo $a # 9
  5. let "a = 5 + 4"
  6. echo $a # 9
  7. let a++
  8. echo $a # 10
  9. let "a = 4 * 5"
  10. echo $a # 20
  11. let "a = $1 + 30"
  12. echo $a # 30 + first command line argument

Let's break it down:

  • Line 4 - This is the basic format. Note that if we don't put quotes around the expression then it must be written with no spaces.
  • Line 7 - This time we have used quotes which allow us to space out the expression to make it more readable.
  • Line 10 - This is a shorthand for increment the value of the variable a by 1. It is the same as writing "a = a + 1".
  • Line 16 - We may also include other variables in the expression.
  1. ./let_example.sh 15
  2. 9
  3. 9
  4. 10
  5. 20
  6. 45

Here is a table with some of the basic expressions you may perform. There are others but these are the most commonly used.

Operator Operation
+, -, \*, / addition, subtraction, multiply, divide
var++ Increase the variable var by 1
var-- Decrease the variable var by 1
% Modulus (Return the remainder after division)

These operators may be used in the other mechanisms described below as well.

Expr

expr is similar to let except instead of saving the result to a variable it instead prints the answer. Unlike let you don't need to enclose the expression in quotes. You also must have spaces between the items of the expression. It is also common to use expr within command substitution to save the output to a variable.

expr item1 operator item2

Let's look at a simple example:

expr_example.sh

  1. #!/bin/bash
  2. # Basic arithmetic using expr
  3. expr 5 + 4
  4. expr "5 + 4"
  5. expr 5+4
  6. expr 5 \* $1
  7. expr 11 % 2
  8. a=$( expr 10 - 3 )
  9. echo $a # 7

Let's break it down:

  • Line 4 - This is the basic format. Note that there must be spaces between the items and no quotes.
  • Line 6 - If we do put quotes around the expression then the expression will not be evaluated but printed instead.
  • Line 8 - If we do not put spaces between the items of the expression then the expression will not be evaluated but printed instead.
  • Line 10 - Some characters have a special meaning to Bash so we must escape them (put a backslash in front of) to remove their special meaning.
  • Line 12 - Here we demonstrate the operator modulus. The modulus is the remainder when the first item is divided by the second item.
  • Line 14 - This time we're using expr within command substitution in order to save the result to the variable a.
  1. ./expr_example.sh 12
  2. 9
  3. 5 + 4
  4. 5+4
  5. 60
  6. 1
  7. 7

Double Parentheses

In the section on Variables we saw that we could save the output of a command easily to a variable. It turns out that this mechanism is also able to do basic arithmetic for us if we tweak the syntax a little. We do so by using double brackets like so:

$(( expression ))

Here's an example to illustrate:

expansion_example.sh

  1. #!/bin/bash
  2. # Basic arithmetic using double parentheses
  3. a=$(( 4 + 5 ))
  4. echo $a # 9
  5. a=$((3+5))
  6. echo $a # 8
  7. b=$(( a + 3 ))
  8. echo $b # 11
  9. b=$(( $a + 4 ))
  10. echo $b # 12
  11. (( b++ ))
  12. echo $b # 13
  13. (( b += 3 ))
  14. echo $b # 16
  15. a=$(( 4 * 5 ))
  16. echo $a # 20

Let's break it down:

  • Line 4 - This is the basic format. As you can see we may space it out nicely for readability without the need for quotes.
  • Line 7 - As you can see, it works just the same if we take spacing out.
  • Line 10 - We may include variables without the preceding $ sign.
  • Line 13 - Variables can be included with the $ sign if you prefer.
  • Line 16 - This is a slightly different form. Here the value of the variable b is incremented by 1 (using the same mechanism illustrated under let). When we do this we don't need the $ sign preceding the brackets.
  • Line 19 - This is a slightly different form of the previous example. Here the value of the variable b is incremented by 3. It is a shorthand for b = b + 3.
  • Line 19 - Unlike other methods, when we do multiplication we don't need to escape the * sign.
  1. ./expansion_example.sh
  2. 9
  3. 8
  4. 11
  5. 12
  6. 13
  7. 16
  8. 20

So as you can see double parenthese is quite flexible in how you format it's expression. This is part of why we prefer this method. As double parentheses is builtin to Bash it also runs slighly more efficiently (though to be honest, with the raw computing power of machines these days the difference in performance is really insignificant).

Length of a Variable

This isn't really arithmetic but it can be quite useful. If you want to find out the lengh of a variable (how many characters) you can do the following:

${#variable}

Here's an example:

length_example.sh

  1. #!/bin/bash
  2. # Show the length of a variable.
  3. a='Hello World'
  4. echo ${#a} # 11
  5. b=4953
  6. echo ${#b} # 4
  1. ./length_example.sh
  2. 11
  3. 4

Summary

let expression
Make a variable equal to an expression.
expr expression
print out the result of the expression.
$(( expression ))
Return the result of the expression.
${#var}
Return the length of the variable var.
Arithmetic
There are several ways in which to do arithmetic in Bash scripts. Double parentheses is the preferred method.
Formatting
When doing arithmetic, the presence or absence of spaces (and quotes) is often important.

Activities

Let's dive in with arithmetic.

  • Create a simple script which will take two command line arguments and then multiply them together using each of the methods detailed above.
  • Write a Bash script which will print tomorrows date. (Hint: use the command date)
  • Remember when we looked at variables we discovered $RANDOM will return a random number. This number is between 0 and 32767 which is not always the most useful. Let's write a script which will use this variable and some arithmetic (hint: play with modulus) to return a random number between 0 and 100.
  • Now let's play with the previous script. Modify it so that you can specify as a command line argument the upper limit of the random number. Can you make it so that a lower limit can be specified also? eg. if I ran ./random.sh 10 45 it would only return random numbers between 10 and 45.