keepcalculator

06 Numbers and Powers

Bash Math Operations: Syntax and Examples

Card No. 06·55621 · Updated · Standard formula, shown below

The calculator on this card is switched off while it is checked. The formula is below, and the worked example shows how to do the sum by hand.

Bash performs basic mathematical operations using arithmetic expansion $((...)), the let command, the expr utility, and the bc calculator for floating-point numbers. You enter an expression like $((5 + 3)) and bash prints the integer result, which is 8 in that case.

Formula

The calculator above applies the standard binary operation you select to two non-negative integers a and b. The result is:

  • Addition: a + b
  • Subtraction: a - b
  • Multiplication: a * b
  • Division: a / b (integer division, truncating toward zero)
  • Modulo: a % b (remainder after division)
  • Power: a ^ b (exponentiation)

All inputs are integers. Division and modulo require b to be non-zero; the calculator prevents that by setting the minimum of b to 1. The result is a single number with up to two decimal places, though for integer inputs the result is always an integer except when using the power operation with large exponents that exceed the display precision.

Worked Example

Using the default values from the block: a = 12, b = 7, and the operation is Addition. The expression evaluates as:

  1. Identify the operation: Addition, so we use a + b.
  2. Substitute the values: 12 + 7.
  3. Compute the sum: 19.

The calculator shows 19 as the result. If you change the operation to Division, the expression becomes 12 / 7 which equals 1 in integer arithmetic (since 7 goes into 12 once, remainder 5). The Modulo operation would give 5.

Arithmetic Expansion: The Core Method

The most common way to do math in bash is arithmetic expansion. You write $(( expression )) and bash evaluates the expression, replacing the whole construct with the numeric result. For example:

echo $(( 10 + 5 ))

This prints 15. The expression can include variables, spaces are optional, and the result is always an integer. Bash supports the standard operators: + (addition), - (subtraction), * (multiplication), / (integer division), % (modulo/remainder), and ** (exponentiation). Parentheses control precedence, and you can nest them freely.

Variables inside arithmetic expansion are treated as numbers automatically. You do not need the dollar sign before variable names inside $((...)), though using it does not cause an error. For instance, $(( a + b )) and $(( $a + $b )) both work. The latter is slightly slower but more explicit.

Bash also supports increment and decrement operators: i++, i--, ++i, --i. These are useful in loops. For example, for ((i=0; i<5; i++)) is a classic C-style for loop that relies on arithmetic evaluation.

Integer Division and Remainders

A key limitation of bash arithmetic is that it only handles integers. When you divide two numbers, bash truncates the fractional part, effectively rounding toward zero. So $(( 7 / 2 )) gives 3, not 3.5. Similarly, $(( -7 / 2 )) gives -3 because truncation moves toward zero, not toward negative infinity.

The modulo operator % returns the remainder after division. $(( 7 % 2 )) gives 1. The sign of the result follows the dividend (the first operand) in bash. So $(( -7 % 2 )) gives -1, while $(( 7 % -2 )) gives 1. This is consistent with the C programming language, which bash follows.

If you need a true quotient with decimals, you must use an external tool. The bc calculator is the standard choice. For example, echo "scale=2; 7/2" | bc prints 3.50. The scale variable sets the number of decimal places. Alternatively, you can use awk or python3 if they are installed, but bc is lightweight and almost always present on Linux systems.

Other Commands: let, expr, and declare

Besides arithmetic expansion, bash offers several other ways to compute. The let built-in evaluates expressions and assigns the result to a variable. For example, let "result = 10 + 5" sets result to 15. You can omit the quotes if the expression has no spaces, but quotes are safer when using operators like * that the shell would otherwise interpret as a glob pattern.

The expr command is an external utility that also evaluates expressions. It is older and slower than built-in arithmetic, but it appears in many legacy scripts. To use it, you must escape or quote the multiplication operator: expr 10 \* 5 or expr 10 "*" 5. The output is printed to stdout, so you capture it with command substitution: result=$(expr 10 + 5).

The declare built-in with the -i flag marks a variable as an integer. Once marked, assignments to that variable are evaluated as arithmetic automatically. For example:

declare -i x
x=10+5
echo $x   # prints 15

This approach is convenient but less common in modern scripts. The ((...)) syntax (without the dollar sign) is a conditional command that returns an exit status based on whether the expression evaluates to non-zero. It is often used in if statements and loops: if (( a > b )); then ....

Floating-Point Math with bc and awk

When you need fractions, square roots, or trigonometric functions, bash alone cannot help. The bc utility is a full calculator language. It supports arbitrary precision, variables, functions, and control structures. A simple division with two decimal places:

echo "scale=2; 22/7" | bc

Output: 3.14. To store the result in a variable: pi=$(echo "scale=4; 22/7" | bc). For more complex math, bc includes functions like s(x) (sine), c(x) (cosine), a(x) (arctangent), l(x) (natural log), and e(x) (exponential). You must load the math library with the -l flag: echo "scale=4; s(1)" | bc -l.

Alternatively, awk can handle floating-point arithmetic natively. For example, awk 'BEGIN {print 22/7}' prints 3.14286 with default precision. Awk is more powerful for processing columns of data, but for a single calculation bc is simpler and more predictable.

Common Pitfalls and Mistakes

Several errors trip up beginners and even experienced scripters. The most frequent is forgetting that bash arithmetic is integer-only. A script that computes $(( 1 / 3 )) silently returns 0, which can cause logic bugs. Always check whether the operation requires decimals and switch to bc if it does.

Another mistake is using the wrong operator for exponentiation. Bash uses ** for powers, not ^. The caret ^ is a bitwise XOR operator in bash arithmetic. So $(( 2 ^ 3 )) gives 1 (because 2 XOR 3 = 1), not 8. This is a common source of confusion for people coming from other languages.

Division by zero causes an error. Bash prints an error message and the expression evaluates to 0, but the script continues unless you check the exit status. Always validate the divisor before dividing, especially when it comes from user input or a file.

Spacing matters in some contexts. In let, spaces around operators are allowed only if the whole expression is quoted. In expr, every operand and operator must be a separate argument, so spaces are mandatory. In $((...)), spaces are optional and ignored.

Performance and Portability

Arithmetic expansion and let are bash built-ins, so they are fast because they do not spawn a new process. expr and bc are external programs, so each invocation forks a subprocess. In a loop that runs thousands of times, this overhead becomes noticeable. Prefer built-in arithmetic for performance-critical loops.

Portability is another consideration. Arithmetic expansion $((...)) is POSIX-compliant and works in other shells like sh, dash, and zsh. The let command and ((...)) syntax are bash-specific, so scripts using them will not run under plain sh. The ** exponentiation operator is also not POSIX, so use pow via bc or a loop if you need strict POSIX compliance.

Frequently Asked Questions

Why does 1/3 give 0 in bash?

Because bash arithmetic only works with integers. The division operator / truncates the fractional part, so 1/3 becomes 0. To get a decimal result, use bc: echo "scale=3; 1/3" | bc prints .333.

How do I calculate a percentage in bash?

Multiply first to avoid losing precision. For example, to find 20% of 150, compute $(( 150 * 20 / 100 )) which gives 30. If you divide first, $(( 150 / 100 * 20 )) gives 20 because 150/100 truncates to 1.

Can bash handle negative numbers?

Yes. Arithmetic expansion supports negative integers. For example, $(( -5 + 3 )) gives -2. Division truncates toward zero, so $(( -7 / 2 )) gives -3, not -4.

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

$((...)) expands to the numeric value of the expression, so you can assign it to a variable or print it. ((...)) evaluates the expression but produces no output; it only returns an exit status (0 if the result is non-zero, 1 if zero). Use ((...)) in conditions and loops.

Is there a way to do floating-point comparison in bash?

Bash cannot compare floats directly. Use bc to compare: if [ $(echo "1.5 > 1.2" | bc) -eq 1 ]; then .... The bc command prints 1 for true and 0 for false.

How do I increment a variable in a bash loop?

Use ((i++)) or i=$((i + 1)). The first is concise and common. In a C-style for loop, you can write for ((i=0; i<10; i++)) directly.

Related

Formula used
in a | First number | - | 12 | 0 | 100000
in b | Second number | - | 7 | 0 | 100000
sel op | Operation | Addition=1, Subtraction=2, Multiplication=3, Division=4, Modulo=5, Power=6
out result | Result | - | (op==1?a+b:op==2?a-b:op==3?a*b:op==4?a/b:op==5?a%b:pow(a,b)) | 2

Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →