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

GroupOperators
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 )) is 1, not 1.5.
  • Leading zeros mean octal — use 10# to force decimal.
  • $(( )) is not valid inside [ ]; use (( )) or [[ ]] with -eq.
  • Comparison inside (( )) uses <, not -lt.