Key Takeaways
- The Linux Bash shell only supports integer arithmetic and cannot perform calculations on floating point numbers.
- The bc utility in Linux allows for precision floating point calculations interactively and in shell scripts.
- Using bc, you can set the number of decimal places to display and perform calculations with arbitrary precision, including using functions from the standard math library.
The Linux Bash shell supports integer arithmetic only. It can neither understand nor cope with floating point calculations. The bc utility gives you precision floating point calculations interactively and in shell scripts.
Why Bash Only Supports Integers
The original design decision to restrict the Unix Bourne shell to integer arithmetic might be rooted in the early-computing mapping of an integer to a single byte of RAM. We may never know what was truly behind the decision. Nor, for that matter, why the Linux version of the Bourne shell, the Bash shell, chose to follow suit.
On its own, Bash cannot perform calculations on floating point numbers, and calculations on integers that would have a fractional part to the answer, are reported as truncated integer values. This is true on the command line and in Bash shell scripts. Depending on your use case, this can be problematic or show-stopping.
Linux comes with two utility applications that allow you to perform floating point calculations. One of these is dc. It’s a bit of a curio, operating as it does in reverse-Polish notation. The other tool is bc. It can be used interactively or as a command, and it’s the solution we’ll discuss here.
The Problem
Let’s get Bash to divide six by three.
echo $((6 / 3))
We get our expected answer of two. Now let’s divide six by seven. Clearly, that will have a fractional answer.
echo $((6 / 7))
Zero is obviously wrong. Let’s try again, dividing 16 by 7.
echo $((16 / 7))
We get an answer of two. What’s happening is the fractional part of the answer is being discarded, so the answer is truncated. There was no fractional part in the first example, so we get the correct answer.
The second example had no integer element in the answer, only a fractional part. Because the fractional part has been discarded the answer we’re shown is zero.
In the third example, 7 divides into 16 twice, with a fractional remainder. Again, the remainder is discarded, and the result is truncated.
Using bc Interactively
You can use bc as an interactive calculator by typing bc and pressing the “Enter” key.
bc
The bc application launches, announces its version number, and then waits for your input. Typing a calculation and pressing “Enter” causes bc to evaluate the calculation and display the answer.
16 * 41024 / 32
2^2 * 1024
You can use “Ctrl+L” to clear the screen, and “Ctrl+D” to exit from the program. Let’s try a calculation that will have a fractional component in the answer.
22 / 7
That’s not what we expected. Counterintuitively, although bc allows us to use arbitrary precision, by default it won’t display the decimal point nor any figures that follow it.
To make the true answer visible we need to tell bc how many decimal places to display. We do this with the “scale” command. We’ll ask for seven decimal places, and re-do our calculation.
scale=7
22 / 7
Finally, we’re getting somewhere. The “scale” setting remains in place until you change it. Setting the number of decimal places tells bc the maximum number of places to display. If an answer doesn’t need that many decimal places, it’s displayed with the number of decimal places it requires and no more. It doesn’t get padded with meaningless zeroes.
scale=10
0.300003 * 0.5
You can list different calculations on the same line by using a semicolon “;” to separate them. The answers are displayed on per line as usual, in the order the calculations were listed.
25 * 6; 12.5 + 45.001; 3 + 5 + 7 + 9
You can include the “scale” command in the list, too.
scale=8; 22 / 7; scale=3; 0.3 * 0.071
The Standard Math Library
The -l (standard math library) option causes bc to load a set of functions, and sets “scale” to 20 decimal places.
bc -l
22 / 7
With the standard library loaded, you can use these functions in your calculations.
- s (x): The sine of x
- c (x): The cosine of x.
- a (x): The arctangent of x
- l (x): The natural logarithm of x
- e (x): The exponential of e to the value x
- j (n,x): The Bessel function of integer order n of x.
Sine, cosine, and arctangent use radian values.
s (1.1)
c (.891207)
a (.628473)
Sending Input to bc on the Command Line
You can use redirection and pipes to send input to bc. It processes your input and displays the answer in the terminal window.
You can redirect into bc with or without the -l (standard math library) option.
bc <<< 22/7
bc -l <<< 22/7
To pipe input to bc, the input has to be the output of another process. It’s convenient to use echo for this.
echo 22/7 | bc
echo 22/7 | bc -l
If you have spaces in your input, or want to include the “scale” command, wrap your input in quotation marks.
echo "22 / 7" | bc -l
echo "scale=6; 22 / 7" | bc
Using bc in Bash Shell Scripts
We’ve now got all we need to be able to perform floating point calculations in our bash scripts, to our chosen precision. We can also reference Bash variables in our calculations, including parameters to the script.
Here’s our example script. Copy this text into an editor, save it as “pi.sh”, then close your editor.
#!/bin/bashfirst_number=22
second_number=7
pi=$(echo "scale=$1; $first_number/$second_number" | bc)
echo "Pi to $1 decimal places is: $pi"
We use two variables, “first_number” and “second_number” to hold two numerical values. We use those variables in the input that we’re piping into bc.
We’ve also used the first command line parameter passed to the script, “$1”, as the value to set “scale” to.
Before we can try our script, we need to make it executable with chmod.
chmod +x pi.sh
Let’s try our script with different command line values.
./pi.sh 5
./pi.sh 14
./pi.sh 20
We get pi displayed to number of places we specify on the command line to our script.
It All Adds Up
Moving beyond the limitations of Bash’s integer-only mathematics gives our scripts precision and accuracy.
Using echo to pipe input to bc inside scripts is a little clunky, but it works perfectly well, and the benefits are worth it.