How to Perform Arithmetic in Bash

How to Perform Arithmetic in Bash

How to Perform Arithmetic in Bash

Bash wasn’t originally designed as a math-heavy language, but I still end up doing arithmetic in almost every script I write — counting iterations, calculating percentages, converting units, you name it. The tricky part is that Bash has several different ways to do math, and each has its own quirks. In this guide, I’ll walk through all of them so you know exactly which one to reach for.

Why Arithmetic in Bash Is a Bit Different

Unlike languages like Python or JavaScript, Bash treats everything as a string by default. If you write x = 5 + 3, Bash won’t automatically calculate anything — you need to explicitly tell it you want arithmetic evaluation. There are four main ways to do that:

  1. $(( )) — arithmetic expansion
  2. (( )) — arithmetic evaluation (for conditions/increments)
  3. let — the older arithmetic command
  4. expr — an external command for expressions (largely legacy now)

Let’s go through each.

Using $(( )) — Arithmetic Expansion

This is the most common and recommended way to perform arithmetic in Bash.

Example 1: Basic Operations

#!/bin/bash

a=10
b=3

echo "Addition: $((a + b))"
echo "Subtraction: $((a - b))"
echo "Multiplication: $((a * b))"
echo "Division: $((a / b))"
echo "Modulus: $((a % b))"
echo "Exponentiation: $((a ** b))"

Output:

Addition: 13
Subtraction: 7
Multiplication: 30
Division: 3
Modulus: 1
Exponentiation: 1000

Notice that a / b gives 3, not 3.33. Bash only supports integer arithmetic natively — there’s no built-in floating-point support. I’ll show you how to work around that later using bc.

Example 2: Storing the Result in a Variable

#!/bin/bash

x=15
y=4
result=$((x + y))
echo "The result is: $result"

Output:

The result is: 19

Using (( )) — Arithmetic Evaluation

(( )) is typically used for evaluating expressions as a command, particularly for incrementing/decrementing variables or as a condition.

Example: Incrementing and Decrementing

#!/bin/bash

count=5
((count++))
echo "After increment: $count"

((count--))
echo "After decrement: $count"

Output:

After increment: 6
After decrement: 5

Example: Using (( )) in a Condition

#!/bin/bash

num=10

if (( num > 5 ))
then
    echo "$num is greater than 5"
fi

Output:

10 is greater than 5

Notice that inside (( )), you don’t need $ before variable names, and you can use normal mathematical operators like >, <, == directly, unlike inside [ ].

Using let

let is an older command for performing arithmetic and assigning the result to a variable.

#!/bin/bash

let result=5+3
echo "Result: $result"

let "result = result * 2"
echo "Doubled: $result"

Output:

Result: 8
Doubled: 16

I rarely use let in new scripts since $(( )) and (( )) are more consistent and readable, but you’ll still see it in a lot of older scripts.

Using expr (Legacy)

expr is an external command, meaning it spawns a separate process every time you call it — which makes it slower than the other methods. It also requires spaces around every operator and symbol.

#!/bin/bash

result=$(expr 5 + 3)
echo "Result: $result"

Output:

Result: 8

Be careful: expr 5*3 will fail or behave strangely because * is interpreted as a glob by the shell unless escaped (expr 5 \* 3). This is one of many reasons expr has fallen out of favor.

Floating-Point Arithmetic with bc

Since Bash only handles integers natively, you need an external tool for decimal calculations. bc (basic calculator) is the standard choice.

Example 1: Simple Division

#!/bin/bash

result=$(echo "10 / 3" | bc -l)
echo "Result: $result"

Output:

Result: 3.33333333333333333333

The -l flag loads the math library, which also gives you access to functions like sqrt(), sin(), and more precision.

Example 2: Rounding to a Fixed Number of Decimal Places

#!/bin/bash

result=$(echo "scale=2; 10 / 3" | bc)
echo "Result: $result"

Output:

Result: 3.33

scale=2 tells bc to keep two digits after the decimal point.

Example 3: Calculating Percentages

#!/bin/bash

total=250
part=47

percentage=$(echo "scale=2; ($part / $total) * 100" | bc)
echo "Percentage: $percentage%"

Output:

Percentage: 18.80%

Alternative: Using awk for Floating-Point Math

If bc isn’t installed on a system (rare, but possible on minimal containers), awk is a solid fallback:

#!/bin/bash

result=$(awk "BEGIN {print 10/3}")
echo "Result: $result"

Output:

Result: 3.33333

How This Works Internally

Real-World Use Cases

used=$(df / | tail -1 | awk '{print $3}')
total=$(df / | tail -1 | awk '{print $2}')
percent=$(echo "scale=2; ($used/$total)*100" | bc)
echo "Disk usage: $percent%"
total=0
for i in {1..10}
do
    ((total += i))
done
echo "Sum of 1 to 10: $total"
celsius=25
fahrenheit=$(echo "scale=2; ($celsius * 9/5) + 32" | bc)
echo "$celsius°C is $fahrenheit°F"
total_time=0
count=0
while read -r time
do
    total_time=$(echo "$total_time + $time" | bc)
    ((count++))
done < response_times.txt
average=$(echo "scale=2; $total_time / $count" | bc)
echo "Average response time: $average ms"

Best Practices

Security Considerations

Optimization Tips

Troubleshooting Common Issues

Frequently Asked Questions

Q: Does Bash support floating-point arithmetic natively? A: No. Bash’s built-in arithmetic ($(( )), (( )), let) only supports integers. Use bc or awk for decimals.

Q: What’s the fastest way to do arithmetic in Bash? A: $(( )) and (( )), since they’re handled internally by Bash without spawning a new process.

Q: How do I round a number in Bash? A: Use bc with a specific scale, or printf "%.2f" for formatted rounding of a value already computed.

Q: Can I use variables without a $ sign inside (( ))? A: Yes — inside arithmetic contexts like (( )), Bash automatically treats bare variable names as their numeric values.

Common Mistakes to Avoid

Summary

Bash gives you several ways to do math, but they’re not interchangeable. For everyday integer arithmetic, $(( )) and (( )) are fast, clean, and built right into the shell. When you need decimals or advanced math functions, reach for bc (or awk as a fallback). Avoid expr unless you’re maintaining older scripts that already use it. Once you know which tool fits which job, arithmetic in Bash becomes second nature.

References

Exit mobile version