If you don't need floating point precision in your arithmatic, and your arithmatic isn't complicated, the fastest way to do this is with the arithmatic expansion operator $(( ))
#!/bin/bash
sum=$(( 4 + 4 ))
echo $sum
difference=$(( 4 - 4 ))
echo $difference
product=$(( 4 * 4 ))
echo $product
quotient=$(( 4 / 4 ))
echo $quotient
remainder=$(( 4 % 4 ))
echo $remainder
If you need floating point precision, the most common way of doing this is by calling the bc command. Usually this is done like this.
sum=$(echo "scale=3; 4 + 4" | bc)
#This can also do more complicated math.
sum=$(echo "scale=3; "2 * ( 4 + 4 ) / 4" | bc)
If you have a lot of calculations to do, the above method of command substitution is very, very slow. Each command substitution call is an execve, and each has to have it's output captured to a variable. This overhead adds up fairly quickly.
Here is the fastest way to do a lot of math in bash. Say we have file like the following and you want to divide the numbers in the right column by the numbers in the left column to a decimal precision of 5 digits.
22.22 48.583
24.1 24.594
29.389 283.298
294.293 29.1
...
92.2 19.494
Here's the code that will do it very quickly.
#!/bin/bash
##
# Make some fifos we can connect to.
##
mkfifo /tmp/bc.in
mkfifo /tmp/bc.out
##
# Attach file descriptors to those fifos.
##
exec 7<>/tmp/bc.in
exec 8<>/tmp/bc.out
##
# Start a single bc process in background and connect our fds to
# it's stdin, stdout, stderr we can use to do all of our math. We can
# do this because bc is an interpreter, with it's own shell. Using
# these same methods we can do inline perl/php/python, etc in
# bash.
##
bc 0<&7 1>&8 2>&8 &
while read numerator denominator
do
echo "scale=5; $numerator / $denominator" >&7
read quotient <&8
# bc errors have ':' in them somewhere.
if [ "$quotient" != "${quotient//:/}" ; then
echo "Error: $quotient"
else
echo "Answer of $numerator / $denominator is $quotient."
fi
done
##
# Shutdown our bc process
##
echo "quit" >&7
##
# Close down our file descriptors.
##
exec 7>&-
exec 7<&-
exec 8>&-
exec 8<&-