Bash Arithmetic: $(( )), (( )) and Decimal Math

Tested on RHEL 10.2 (Coughlan)
Package bash 5.2.26-6.el10
gawk 5.3.0-8.el10
bc 1.08.2-5.el10
Applies to Linux distributions with Bash installed
Privilege Normal user; no root required for the examples
Scope Integer arithmetic with $(( )) and (( )), operators, increment and decrement, for (( )) loops, number bases, division and remainder, declare -i, legacy let and expr, and decimal work with awk or bc. Does not cover full numeric comparison syntax in [[ ]] or advanced floating-point libraries.
Related guides Bash shell script tutorial
Shell scripting course hub
Short on time?Beta Get the gist of this 10-minute read in seconds, then ask follow-up questions

Bash provides arithmetic contexts for evaluating integer expressions directly in shell scripts. Use $(( )) when you need the calculated value in an assignment or command line. Use (( )) when you want to test an arithmetic expression or update variables directly.

Bash handles integer arithmetic natively. For decimal calculations, awk and bc are two common choices. The main difference is whether you need the calculated value from $(( )) or need (( )) to run as a command with an exit status.


Why result=$a+$b Does Not Perform Arithmetic

Normal shell assignment does not calculate. It stores the text on the right of =:

bash
a=5
b=3
result=$a+$b
printf '%s\n' "$result"
output
5+3

Bash expanded the variables but treated + as ordinary text, so the assigned value became 5+3. To add the numbers, use arithmetic expansion:

bash
result=$((a + b))
printf '%s\n' "$result"
output
8

$(( expression )) is Bash arithmetic expansion: it evaluates an integer expression and substitutes the result.


Bash Arithmetic in One Table

Form What it does Typical use
$(( expression )) Arithmetic expansion — substitutes the numeric result total=$((a + b)), printf '%s\n' "$((n ** 2))"
(( expression )) Arithmetic command — evaluates expressions, can update variables, and returns status 0 for nonzero or 1 for zero (( count < max )), ((i++))
declare -i name Integer attribute on assignment declare -i total — values assigned are evaluated as arithmetic
let expression Legacy arithmetic builtin using the same arithmetic expression syntax let "x += 3" — prefer (( )) in new scripts
expr 5 + 3 Older external arithmetic syntax Recognize in legacy scripts; prefer Bash arithmetic in new code

$(( )) returns a value. (( )) is a command: it exits 0 when the expression is nonzero and 1 when the expression evaluates to zero.


Arithmetic Expansion with $(( ))

Use $(( )) when you need the calculated value in an assignment, command argument, or output.

Add two variables:

bash
a=5
b=3
printf 'sum=%s\n' "$((a + b))"
output
sum=8

Spaces inside $(( )) are optional; a+b and a + b both work. Variable names do not need a leading $ inside the parentheses. Bash also evaluates the value of a referenced variable as an arithmetic expression. Keep this in mind when arithmetic operands come from external input.

Assign the result back to a variable:

bash
count=0
count=$((count + 1))
printf 'count=%s\n' "$count"
output
count=1

Nested parentheses group sub-expressions: $(( (a + b) * 2 )).


Arithmetic Command (( ))

(( expression )) evaluates an arithmetic expression without expanding the result into the command line. The expression can modify variables, and its final numeric value determines the exit status: nonzero succeeds with status 0, zero fails with status 1.

Check the exit status when the expression evaluates to zero:

bash
bash -c '(( 0 )); printf "zero exit=%s\n" "$?"'
output
zero exit=1

Use (( )) in if, while, and until when you want a numeric test without $(( )) expansion; the Bash if, elif, else guide covers command-status branching in the same structures:

bash
size_kb=250
limit_kb=100
if (( size_kb > limit_kb )); then
  printf 'over limit\n'
fi
output
over limit

When (( expression )) is used as a standalone command in a context where set -e applies, a zero result can terminate the script. That matters for postfix increment — covered in the increment section below.


Bash Arithmetic Operators

Common Bash arithmetic operators include:

Type Operators
Basic math + - * / % **
Increment/decrement ++ --
Comparison < <= > >= == !=
Logical ! && ||
Bitwise ~ & | ^ << >>
Assignment = += -= *= /= %= <<= >>= &= ^= |=
Conditional condition ? true_value : false_value

Use == and != for equality tests. = is assignment — (( a = b )) stores b into a, it does not compare them.

Raise a value to a power with **:

bash
printf '%s\n' "$((2 ** 3))"
output
8

Combine assignment and addition inside (( )):

bash
x=2
((x += 3))
printf 'x=%s\n' "$x"
output
x=5

Comparisons evaluate to 1 for true and 0 for false:

bash
a=10
b=20
printf 'a<b=%s\n' "$((a < b))"
output
a<b=1

The ternary operator picks one of two values:

bash
count=12
status=$(( count > 10 ? 1 : 0 ))
printf 'status=%s\n' "$status"
output
status=1

For tests outside arithmetic context — for example [[ "$x" -eq 5 ]] — see Bash compare numbers.


Increment, Decrement and Arithmetic Loops

Prefix and postfix forms work inside (( )) and in for (( )) headers: ++var, var++, --var, var--. Variable names in for (( )) do not take a leading $.

A C-style arithmetic loop initializes, compares, and increments in one header. The Bash for loop guide covers list-form loops and other for (( )) patterns:

bash
for ((i = 0; i < 3; i++)); do
  printf 'i=%s\n' "$i"
done
output
i=0
i=1
i=2

A standalone ((i++)) can unexpectedly terminate a script using set -e when i starts at 0. ((i++)) evaluates to 0 on the first bump, so the arithmetic command fails and the script exits:

bash
bash -c 'set -e; i=0; ((i++)); echo after-i++' 2>&1; printf 'exit=%s\n' "$?"
output
exit=1

set -e does not terminate for failures used as tests in if, while, until, and many && / || contexts; see Bash exit codes for when errexit still applies. Prefer i=$((i + 1)) in strict-mode scripts, or see Bash increment variable for post- vs pre-increment patterns.


Number Bases and Leading Zeros

Bash accepts base#number in arithmetic, with bases from 2 through 64. You can also write hexadecimal values with a 0x prefix.

Binary and hexadecimal literals:

bash
printf '%s\n' "$((2#1010))"
output
10

Hexadecimal literals use base 16:

bash
printf '%s\n' "$((16#FF))"
output
255

A leading 0 without base# selects octal. That is why bare 08 fails — 8 is not a valid octal digit:

bash
bash -c 'printf "%s\n" $((08))' 2>&1
output
bash: line 1: 08: value too great for base (error token is "08")

Force base 10 with the 10# prefix:

bash
printf '%s\n' "$((10#08))"
output
8

Parse a zero-padded ID from a variable the same way:

bash
build_id=00042
seq=$((10#$build_id))
printf 'seq=%s\n' "$seq"
output
seq=42

Without 10#, a value such as 010 is octal and evaluates to 8:

bash
declare -i n=010
printf 'n=%s\n' "$n"
output
n=8

If a value is known to contain decimal digits but may be zero-padded, use 10# to force base 10.


Integer Division, Modulo and Division by Zero

Bash arithmetic uses signed integers. Division truncates toward zero; % returns the remainder:

bash
printf 'div=%s rem=%s\n' "$((17 / 5))" "$((17 % 5))"
output
div=3 rem=2

The % operator returns the remainder, which is useful for checks such as whether a number is even: (( n % 2 == 0 )).

Bash uses fixed-width integers and does not check for arithmetic overflow, so sufficiently large values can wrap.

Division by zero is a hard error:

bash
bash -c 'printf "%s\n" $((5 / 0))' 2>&1
output
bash: line 1: 5/0: division by 0 (error token is "0")

Guard divisors before you divide.


Decimal and Floating-Point Math with awk and bc

Bash has no built-in floating-point arithmetic. Use awk for convenient formatted calculations or bc when you need control over calculation scale.

Compute a percentage with awk — printf in awk rounds the displayed value:

bash
awk 'BEGIN{printf "pct=%.1f\n", 3/8*100}'
output
pct=37.5

Pipe an expression to bc:

bash
printf 'scale=2; 3/8\n' | bc
output
.37

For division, scale=2 calculates two digits after the decimal point without rounding, so 3/8 becomes .37, not .38. For rounded decimal output, awk with printf "%.2f" is usually clearer.

Avoid starting a new awk or bc process on every iteration of a large loop when the calculations can be batched into one call.


declare -i, let and Legacy expr

declare -i gives a variable the integer attribute, so values assigned to it are evaluated as arithmetic expressions:

bash
declare -i total
total="2 + 3"
printf 'total=%s\n' "$total"
output
total=5

Unlike a normal assignment, assigning to a declare -i variable performs arithmetic evaluation immediately. See Bash variables for other declare attributes.

The legacy let builtin accepts the same expressions as (( )):

bash
x=2
let "x += 3"
printf 'x=%s\n' "$x"
output
x=5

Older scripts sometimes call expr as an external command:

bash
expr 5 + 3
output
8

Recognize expr when reading legacy code; prefer $(( )) or (( )) in new scripts.


Common Bash Arithmetic Errors

Symptom Likely cause Fix
5+3 instead of 8 Normal assignment, not arithmetic Use $((a + b))
value too great for base on 08 or 09 Leading zero implies octal Use $((10#08)) or strip leading zeros
Script exits under set -e on ((i++)) Postfix increment returned 0 as standalone command Use i=$((i + 1))
division by 0 Divisor was zero Test the divisor before / or %
3 / 8 prints 0 Integer division truncates Use awk or bc for decimal math
Missing variable behaves like 0 Without set -u, unset or null variables in arithmetic normally evaluate as 0; with set -u, an unset variable is an error Initialize variables; account for set -u
bc shows .37 not .38 scale truncates; does not round Use awk printf for rounded display

Bash Percentage and Threshold Example

This example uses Bash arithmetic for the integer threshold comparison and awk to calculate the percentage. With a known nonzero limit, compare two integer counts:

bash
used_kb=85
limit_kb=100
if (( used_kb > limit_kb )); then
  printf 'over limit: %s/%s KB\n' "$used_kb" "$limit_kb"
else
  pct=$(awk -v u="$used_kb" -v l="$limit_kb" 'BEGIN{printf "%.0f", u/l*100}')
  printf 'within limit: %s%% (%s/%s KB)\n' "$pct" "$used_kb" "$limit_kb"
fi
output
within limit: 85% (85/100 KB)

Summary

Bash evaluates integer expressions with $(( )) when you need the result and (( )) when you need an arithmetic command for tests or updates. Normal assignment does not calculate; use $((a + b)) rather than $a+$b.

Bash arithmetic is integer-only. Division truncates fractional results, and leading zeros can trigger octal interpretation. Use awk or bc when you need decimal calculations.


References


Frequently Asked Questions

What is the difference between (( )) and $(( ))?

$(( expression )) evaluates the expression and substitutes the result, so you can assign it or print it. (( expression )) runs as a command: it can modify variables, and its final value sets exit status (0 when nonzero, 1 when zero). Use $(( )) for values and (( )) for tests and direct updates.

Does Bash support floating point?

Not in native shell arithmetic. $(( )) and (( )) work on integers only. Use awk for formatted decimal calculations or bc when you need controlled calculation scale.

Why does 08 fail in Bash arithmetic?

A leading 0 selects base 8 (octal). 8 and 9 are not valid octal digits, so 08 errors. Use $((10#08)) when the input is decimal text with a leading zero.

Why can ((i++)) stop a strict-mode script?

Postfix ((i++)) evaluates to the old value. When i is 0, that value is 0, so a standalone (( )) command can exit with status 1. With set -e in an applicable context, the script terminates. Use i=$((i + 1)) or read the increment guide for other patterns.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)