Main index

# 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:
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:

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`.