Dealing with float numbers in bash can be a bit tricky since bash natively supports only integer arithmetic. However, you can perform floating-point arithmetic using external tools. Here we will walk through few methods to handle floating-point numbers in bash.
When dealing with integers, all is simple. See this example:
[root@linux ~]# echo $((2+2))
4
[root@linux ~]# x=2; y=3
[root@linux ~]# echo $((x+y))
5
[root@linux ~]#
However, when it comes to float numbers, this approach wouldn’t work. You need to invoke some external command which would be able to process float numbers and perform arithmetic operations with them. As in any other case, *nix world has many different solutions for the same problem, and float calculations is not an exception. You can use bc
, awk
, dc
, perl
, python
…
bc
I personally prefer bc
over anything else. It is designed exactly for the purpose of calculations, so why not use it? The only disadvantage which I noticed is that in some cases it might be slower than awk
.
[root@linux ~]# echo "3.5 * 2.12345" | bc
7.43207
[root@linux ~]#
[root@linux ~]# echo "scale=4; 1 / 3" | bc
.3333
[root@linux ~]#
Small thing worth to mention here is leading zero, which is missing. To fix it, you can use printf
like:
[root@linux ~]# printf "%.4f\n" "$(echo "scale=4; 1 / 3" | bc)"
0.3333
[root@linux ~]#
awk
While awk
can perform arithmetic operations, its primary strength lies in text processing. If your script needs to combine text processing with arithmetic, awk
can be more convenient.
[root@linux ~]# awk 'BEGIN {print 3.5 + 2.11}'
5.61
[root@linux ~]#
Benchmark testing of bash float number operations
Finally, we can perform some benchmark tests. Here is the script which you can try yourself and choose whatever suits you best:
#!/bin/bash
iterations=10000
echo "Using bc:"
time for i in $(seq 1 $iterations); do
result=$(echo "3.5 * 2.1" | bc)
done
echo ""
echo "Using awk:"
time for i in $(seq 1 $iterations); do
result=$(awk 'BEGIN {print 3.5 * 2.1}')
done
echo ""
echo "Using python:"
time for i in $(seq 1 $iterations); do
result=$(python -c "print(3.5 * 2.1)")
done
echo ""
echo "Using perl:"
time for i in $(seq 1 $iterations); do
result=$(perl -e 'print 3.5 * 2.1')
done
echo ""
echo "Using dc:"
time for i in $(seq 1 $iterations); do
result=$(echo "3.5 2.1 * p" | dc)
done
exit 0
Expected results are the following:
awk
: generally performs well and is often faster than bc for simple arithmetic operationsbc
: has some overhead due to its precision and capability but performs adequately for complex arithmeticpython
: it has a significant startup time, making it slower for a large number of simple calculationsperl
: similar to python, perl has startup overheaddc
: dc is designed for arbitrary-precision arithmetic and can be efficient, but its usage is less common
Let’s run the test:
[root@linux ~]# ./float.sh
Using bc:
real 0m18.733s
user 0m10.671s
sys 0m11.763s
Using awk:
real 0m14.815s
user 0m5.192s
sys 0m9.593s
Using python:
real 1m55.394s
user 1m16.351s
sys 0m38.699s
Using perl:
real 0m26.210s
user 0m11.537s
sys 0m14.863s
Using dc:
real 0m16.044s
user 0m11.055s
sys 0m8.567s
[root@linux ~]#
Summary
The decision to not support floating-point arithmetic natively in bash is rooted in historical context, design philosophy, and practical considerations. Bash is designed to be a lightweight, efficient scripting environment for command execution and text processing, with the ability to leverage external tools for more complex tasks. This approach aligns with the Unix philosophy of using specialized tools for specific tasks, maintaining simplicity, and ensuring performance.
However, by employing additional external tools you can easily perform arithmetic operations with float numbers in bash and incorporate it easily into your scripts.