Main index

Introducing UNIX and Linux


More on shells

Overview
Simple arithmetic
      Arithmetic expansion
            Operators for arithmetic expansion
      The 'expr' command
Pattern matching
      Patterns
            Examples of patterns
      The case statement
Entering and leaving the shell
More about scripts with options
Symbolic links
Setting up terminals
Conventions used in UNIX file systems
Summary
Exercises

Arithmetic expansion

The utility bc was discussed in the previous chapter, and will perform any calculations required, to any accuracy, just as if you had a pocket calculator available. Although bc does have all the facilities required, it is in many circumstances 'overkill' - the overheads of calling and executing a utility such as bc are high. It is therefore desirable to have another method of doing simple arithmetic tasks as a part of the shell, thus obviating the need to call a utility like bc. The mechanism is known as arithmetic expansion and takes the form of

$(( expression ))

where expression is a valid arithmetic expression, using only integers (no floating point arithmetic), and the operators described below. On some On some non-POSIX systems, you will need to use $[...] instead of $((...)). Boolean expressions are represented by 1 for True and 0 for False (not to be confused with the shell commands true and false). The operators are a subset of those available in the C programming language, and parentheses may be used to group subexpressions. Thus the following dialogue could take place:

echo $(( 1 + 2 + (3 * 4)))
15
echo $(( 1 > 2 ))
0
echo $(( 1 < 2 ))
1

As an example, the following script will read in a number, assumed to represent pounds weight, and write to the standard output a message translating that to stones and pounds (one stone = 14 pounds):

echo Type in a whole number representing pounds weight:
read POUNDS
STONES=$(( $POUNDS / 14 ))
SMALLPOUNDS=$(( $POUNDS % 14 ))
echo $POUNDS pounds is $STONES and $SMALLPOUNDS pounds

Worked example

Write a script convertsec to read in a number, thought of as representing seconds, and print out the number of hours, minutes and seconds it represents, so:

convertsec
Enter a number of seconds:
12345
12345 seconds is 3:25:45

Solution: First of all, check that the number is not less than zero, and then do the calculation, which is self-explanatory.

# Prompt the user and read in number of seconds
echo Enter a number of seconds:
read SECONDS

if   [ $SECONDS -lt 0 ]            # Check it's positive
then echo Number must be positive
else MINUTES=$(( $SECONDS / 60 ))  # Total minutes
     RSECONDS=$(( $SECONDS % 60 )) # Residual seconds
     HOURS=$(( $MINUTES / 60 ))    # Total hours
     MINUTES=$(( $MINUTES % 60 ))  # Residual minutes
     printf "%d seconds is %d:%02d:%02d\n" $SECONDS \
                      $HOURS $MINUTES $RSECONDS
fi

You may wish to compare arithmetic expansion with using bc. The example in the previous chapter, which displays the '12 times table' would be coded as a script using arithmetic expansion as follows:

i=1
while [ $i -le 12 ]
do
   result=$(( $i * 12 ))
   echo "$i x 12 = $result"
   i=$(( $i + 1 ))
done

Try out both - you will find that when you use arithmetic expansion it is much faster. Where possible, you should use arithmetic expansion in preference to bc, but if you are in any doubt as to whether arithmetic expansion can give you sufficient precision, you should play safe and use bc.


Copyright © 2002 Mike Joy, Stephen Jarvis and Michael Luck