Bash Arithmetic Operators Reference

All (( )) and let arithmetic operators with precedence and assignment forms.

Reference for Bash arithmetic expansion operators usable in $(( )), (( )) and let — covering arithmetic, bitwise, shift, comparison, logical, ternary and compound assignment, each ranked by precedence with a worked example. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

Does Bash arithmetic support decimals?

No. Bash arithmetic is integer-only, so division truncates toward zero and there is no floating point. For decimal math, pipe the expression to bc with the -l flag or use awk, which both support real numbers.

Bash arithmetic operators

Bash evaluates integer math inside three constructs: arithmetic expansion $(( expr )) which substitutes the result, the arithmetic command (( expr )) which sets the exit status, and the let builtin. They share one operator set modelled on the C language: arithmetic, bitwise, shifts, comparison, logical, the ternary conditional and compound assignment. This page is a searchable, offline reference that also shows each operator’s precedence so you know when parentheses are required.

How it works

Inside an arithmetic context every token is interpreted numerically. Bare variable names expand to their values automatically, non-numeric strings become zero, and the whole expression yields an integer. Operators are applied in precedence order:

  • Highest binding: post/pre increment, unary sign and ~/!, then **.
  • Then the multiplicative * / %, additive + -, and shifts << >>.
  • Then relational < <= > >=, equality == !=.
  • Then the bitwise trio in order &, ^, | — note these bind looser than the comparisons, a common source of bugs.
  • Then logical && and ||, the ternary ?:, and finally assignment and the comma operator.

Comparison and logical operators return 1 for true and 0 for false, which is why (( x > 0 )) works as a condition: a non-zero result is a success exit status.

Worked examples

Use the arithmetic command directly as a loop condition:

for (( i = 0; i < 5; i++ )); do
  echo "$i squared is $(( i ** 2 ))"
done

Compound assignment keeps counters terse:

total=0
(( total += 25 ))   # total is now 25
(( total <<= 1 ))   # bit-shift left → 50

The ternary operator picks a value inline without an if:

max=$(( a > b ? a : b ))

Common pitfalls and surprising behaviours

Integer division truncates toward zero. $(( 7 / 2 )) is 3, not 3.5. For fractional results, reach for bc -l or awk.

echo "scale=2; 7 / 2" | bc   # prints 3.50
awk 'BEGIN { print 7 / 2 }'  # prints 3.5

Modulo sign follows the dividend. $(( -7 % 3 )) is -1, not 2. This matches C but differs from Python, where the result takes the sign of the divisor.

Bitwise operators bind more loosely than comparisons. This surprises people coming from Python or JavaScript:

# BUG: & binds before ==, so reads as (x & (4 == 0)) not ((x & 4) == 0)
(( x & 4 == 0 ))

# CORRECT: add explicit parentheses
(( (x & 4) == 0 ))

i++ vs ++i in expressions. Both increment by one, but the value yielded differs:

i=5
echo $(( i++ ))   # prints 5; i is now 6
echo $(( ++i ))   # prints 7; i is now 7

Bases in literals. Bash arithmetic supports 0x hex prefix (0xFF) and 0 octal prefix (010 = 8). You can also use base#number notation: $(( 2#1011 )) evaluates the binary literal 1011 = 11.

Remember: Bash arithmetic is always integer-only and always 64-bit signed on modern systems. There is no overflow protection — values wrap around at the 64-bit boundary without warning.