Arithmetic & Math
Integer Arithmetic
Bash computes with signed 64-bit integers only. There is no floating point in the language itself — for decimals you delegate to bc or awk.
Arithmetic Expansion $(( ))
The most common form. Variables inside do not need $.
a=7; b=3
echo $(( a + b )) # 10
echo $(( a - b )) # 4
echo $(( a * b )) # 21
echo $(( a / b )) # 2 (integer division truncates)
echo $(( a % b )) # 1 (remainder)
echo $(( a ** 2 )) # 49 (exponentiation)
let, (( )) and declare -i
let "n = 5" # 'let' evaluates without $(( ))
(( n = n * 2 )) # arithmetic command; its status is 0 if n is non-zero
declare -i k=0 # integer attribute: k=3+4 stores 7
(( )) used as a command returns true (0) when the result is non-zero. That makes it a handy loop condition: while (( n-- )); do ….
Operators
| Group | Operators |
|---|---|
| Arithmetic | + - * / % ** |
| Bitwise | & | ^ ~ << >> |
| Comparison | < <= > >= == != |
| Logical | && || ! |
| Assignment | = += -= *= /= %= |
| Increment | ++ -- (pre and post) |
echo $(( 6 & 3 )) # 2 (bitwise AND)
echo $(( 1 << 4 )) # 16 (shift left)
echo $(( (2 + 3) * 4 ))# 20 (parentheses work normally)
Bases & Overflow
echo $(( 16#ff )) # 255 — hexadecimal input
echo $(( 2#1010 )) # 10 — binary input
echo $(( 8#17 )) # 15 — octal input
printf '%x\n' 255 # ff — format as hex (command, not expansion)
printf '%o\n' 8 # 10 — format as octal
$(( )) leading-zero numbers are read as octal. This bites when a value like 08 arrives from user input:
n=08
echo $(( n + 1 )) # ERROR: value too great for base
echo $(( 10#$n + 1 )) # 9 — force base 10
Overflow wraps silently. Adding 1 to the largest 64-bit integer gives a negative number. For anything financial or scientific, use a real language — not the shell.
Floating Point with bc
bc Basics
bc is an arbitrary-precision calculator. Pipe an expression to it and capture the result.
echo "3 / 2" | bc # 1 (scale defaults to 0)
echo "scale=2; 3 / 2" | bc # 1.50 (two decimal places)
echo "sqrt(2)" | bc -l # 1.41421356237309504880 (-l loads the math library)
Precision and Variables
total=100; count=7
avg=$(echo "scale=2; $total / $count" | bc)
printf 'average = %s\n' "$avg" # average = 14.28
percent=$(echo "scale=1; $count * 100 / $total" | bc)
echo "${percent}%"
Never feed untrusted input straight into
bc — it is a programming language and accepts more than arithmetic. Validate that the value is numeric first with [[ $x =~ ^[0-9.]+$ ]].
Math with awk
awk carries double-precision floats and is already present on every Unix system.
awk 'BEGIN { printf "%.4f\n", 22/7 }' # 3.1429
awk -v a=10 -v b=3 'BEGIN { print a/b }' # 3.33333
seq 1 100 | awk '{ s += $1 } END { print s }' # 5050 — sum a column
Pitfalls
- Integer division truncates:
$(( 3 / 2 ))is1, not1.5. - Leading zeros mean octal — use
10#to force decimal. $(( ))is not valid inside[ ]; use(( ))or[[ ]]with-eq.- Comparison inside
(( ))uses<, not-lt.