Skip to content
Go back

Bash Arithmetic Without bc

By SumGuy 4 min read
Bash Arithmetic Without bc

The Problem with bc

People reach for bc (basic calculator) for arithmetic in bash:

Terminal window
result=$(echo "10 + 5" | bc)
echo $result # 15

This works but spawns a subprocess. It’s slow, verbose, and unnecessary for simple math.

Bash has built-in arithmetic. You just have to know the syntax.

Arithmetic Expansion: $(( ))

Use double parentheses for math:

#!/bin/bash
a=10
b=5
result=$((a + b))
echo $result # 15

That’s it. $(( math )) evaluates the expression and returns the result.

Supported operators:

Terminal window
# Basic
$((10 + 5)) # 15
$((10 - 5)) # 5
$((10 * 5)) # 50
$((10 / 5)) # 2 (integer division)
$((10 % 3)) # 1 (modulo)
$((2 ** 3)) # 8 (exponentiation)
# Assignment
x=5
$((x++)) # post-increment
$((++x)) # pre-increment
$((x += 3)) # add and assign
$((x -= 2)) # subtract and assign
# Comparison
$((5 > 3)) # 1 (true)
$((5 < 3)) # 0 (false)
$((5 == 5)) # 1 (true)
$((5 != 3)) # 1 (true)

Important: arithmetic in bash is integer only. 10 / 3 is 3, not 3.333....

Using Arithmetic in Conditions

Test numbers directly:

Terminal window
if (( count > 10 )); then
echo "More than 10"
fi

(( expression )) is a test. Non-zero is true, zero is false.

Loop with arithmetic:

Terminal window
for (( i=1; i<=5; i++ )); do
echo $i
done
# Output:
# 1
# 2
# 3
# 4
# 5

This is bash’s C-style for loop. Much cleaner than seq.

Real Examples

Disk Usage Check

#!/bin/bash
max_usage=80
current=$( df / | tail -1 | awk '{print $5}' | sed 's/%//' )
if (( current > max_usage )); then
echo "WARNING: Disk $current% full"
fi

Extract the percentage, compare. If over 80%, warn.

Loop and Calculate

#!/bin/bash
total=0
for file in *.log; do
size=$( stat -f%z "$file" 2>/dev/null || stat -c%s "$file" )
((total += size))
done
echo "Total size: $((total / 1024 / 1024)) MB"

Add up file sizes, convert bytes to MB with division.

Countdown Timer

#!/bin/bash
duration=10
while (( duration > 0 )); do
echo "Countdown: $duration"
sleep 1
((duration--))
done
echo "Done!"

Calculate Process Load Average

#!/bin/bash
# Get load average (multiply by 100 to convert to percentage)
load=$( uptime | awk -F'load average:' '{print $2}' | cut -d',' -f1 | xargs )
threshold=2
if (( ${load%.*} >= threshold )); then
echo "System is under heavy load: $load"
fi

Extract the integer part of load, compare to threshold.

Floating Point (When You Need It)

Bash doesn’t do floats natively. But you can fake it with bc when necessary:

Terminal window
# Convert bytes to GB with decimals
bytes=5368709120
gb=$( echo "scale=2; $bytes / 1024 / 1024 / 1024" | bc )
echo "Size: $gb GB" # Size: 5.00 GB

scale=2 means 2 decimal places. But use this sparingly—it’s slow.

For percentages and rounding, integer math is usually enough:

Terminal window
# Progress bar: 3 out of 10 items
items_done=3
items_total=10
percent=$(( items_done * 100 / items_total ))
echo "Progress: $percent%" # Progress: 30%

Pitfall: Variable Expansion in $(( ))

Inside arithmetic expansion, you can use variables without $:

Terminal window
x=5
result=$((x + 10)) # Works
result=$(($x + 10)) # Also works, but unnecessary

Both work. The first is cleaner.

But use $ for clarity in complex expressions:

Terminal window
# This works but is hard to read
result=$((${array[0]} + 5))
# Clearer: expand the variable outside
val=${array[0]}
result=$((val + 5))

Bitwise Operators

Bash also supports bitwise operations:

Terminal window
$((5 & 3)) # AND: 1
$((5 | 3)) # OR: 7
$((5 ^ 3)) # XOR: 6
$((~5)) # NOT: -6 (two's complement)
$((5 << 1)) # Left shift: 10
$((5 >> 1)) # Right shift: 2

Rarely used in sysadmin scripts, but useful for low-level bit manipulation.

Performance Gains

Spawning bc for every calculation is expensive. Here’s a loop that sums 1000 numbers:

Terminal window
# Slow: spawning bc
time {
total=0
for i in {1..1000}; do
total=$( echo "$total + $i" | bc )
done
}
# Fast: builtin arithmetic
time {
total=0
for i in {1..1000}; do
((total += i))
done
}

The builtin version is 10-50x faster. Use it.

Bottom Line

Bash arithmetic with $(( )) handles 95% of shell script math. It’s built-in, fast, and readable. Save bc for the rare case when you need floating-point precision, and even then, consider whether you should be using Python instead.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it may appear here.


Previous Post
Proxy Chains and Anonymization: What Actually Works and What's Just Theater
Next Post
n8n vs Node-RED: Automate Everything Without Learning to Code (Much)

Related Posts