Arithmetic Operations (expr, $(( )))

The shell treats everything as text, so to do maths you ask for it explicitly: the older expr command or the modern dollar-double-parenthesis form, and both work only in whole numbers, so 7 divided by 2 is 3, not 3.5.

10 min read · 7 cards · 2 checks

Read in: English · हिन्दी · ગુજરાતી


Theory

Why n=n+1 does not add

In the shell, values are text by default. So if you write n=5 and then n=n+1, you do not get 6, you get the literal string 'n+1'. The shell did not do any arithmetic, because you did not ask it to.

To actually compute, you must use one of the shell's arithmetic tools. There are two: the older expr command, and the modern $(( )) form. This lesson covers both, and the one limitation that surprises everyone: shell arithmetic is whole numbers only.

Theory

Two ways to compute

expr is an older, external command. You write expr 7 + 3, and it prints 10. It needs spaces around each part, and because * is a wildcard, you must escape multiplication as \*, which is fiddly.

$(( )) is the modern arithmetic expansion built into the shell, and the preferred choice. You write $(( 7 + 3 )) and it becomes 10, no escaping needed, and it reads cleanly. It also powers the common increment idiom you have already seen in loops: i=$((i+1)). Prefer $(( )) in new scripts; recognise expr when you meet it in older ones.

Practical

Arithmetic both ways (verified)

$ expr 7 + 3          # older command
10
$ echo $(( 7 + 3 ))   # modern, preferred
10
$ echo $(( 7 % 2 ))   # modulo (remainder)
1

# The increment idiom used in loops:
$ i=1
$ i=$(( i + 1 ))
$ echo $i
2

Watch out

Integer only: 7 / 2 is 3, not 3.5

Shell arithmetic works in whole numbers only. So $(( 7 / 2 )) is 3, not 3.5, the fractional part is simply thrown away (truncated). There are no decimals at all in expr or $(( )).

If you genuinely need fractions (say, an average or a percentage), the shell cannot do it alone; you use a separate tool such as bc (echo "scale=2; 7/2" | bc gives 3.50) or awk. Forgetting this and expecting 3.5 from $(( 7 / 2 )) is one of the most common shell-scripting surprises.

Quiz

In a shell script, what does echo $(( 7 / 2 )) print?

  1. 3.5, the exact quotient
  2. 3, because shell arithmetic is integer only and truncates the fractional part
  3. 4, rounding up
  4. An error, because division is not allowed
Show the answer

3, because shell arithmetic is integer only and truncates the fractional part

Shell arithmetic works only in whole numbers, so $(( 7 / 2 )) computes the integer quotient and discards the remainder, giving 3 (not 3.5). Option A assumes decimals, which the shell's $(( )) and expr simply do not support. Option C is wrong: it truncates (drops the fraction), it does not round, so 7/2 is 3, and even 9/2 would be 4, not 5. Option D is wrong: division is perfectly allowed; it just yields an integer result. If you need the real value 3.5, you must use a floating-point tool like bc. The takeaway: expect whole-number results from shell maths, and reach for bc when you need fractions.

Think first

Why is shell arithmetic integer-only in the first place?

Most languages handle decimals easily. Why does the shell restrict its built-in maths to whole numbers? Then tap.

Show the answer

Because the shell's job is orchestrating commands and files, not heavy number-crunching, so its built-in arithmetic is kept small and simple, covering the whole-number tasks scripts actually need. Almost all arithmetic in shell scripts is counting and indexing: incrementing a loop counter, counting files, computing a line number, checking how many attempts remain, and those are naturally whole numbers. Supporting full floating-point maths inside the shell would add complexity and edge cases (precision, rounding, formatting) for a need that rarely arises in the shell's core role. So the designers kept it integer-only and left serious or fractional maths to specialised tools that already do it well, bc for arbitrary-precision decimals, awk for calculations over data, Python for anything richer. This reflects the same Unix philosophy you keep meeting: each tool does one thing well and hands off the rest. The shell counts and coordinates; when you need real numbers, you pipe to a calculator built for them. Knowing this, you will not fight the shell for decimals, you will reach for bc without hesitation, and your scripts stay clean.

Summary

Key takeaways

  • The shell treats values as text by default, so n=n+1 does not add; you must ask for arithmetic explicitly.
  • expr is the older external command: expr 7 + 3 prints 10 (spaces required, * must be escaped).
  • $(( )) is the modern, preferred arithmetic expansion: $(( 7 + 3 )) is 10, cleaner and built in.
  • The loop increment idiom i=$(( i + 1 )) uses this; % gives the remainder ($(( 7 % 2 )) is 1).
  • Shell arithmetic is integer only: $(( 7 / 2 )) is 3, not 3.5, the fraction is truncated.
  • For real (fractional) numbers, use a separate tool like bc or awk.
  • Memory hook: $(( )) for whole-number maths; bc when you need decimals.

Study this properly

This page is the lesson to read. In Gri-Learn the same topic is a graded deck: the self-checks are scored and your weak topics are tracked. Free to start.

Start this topic

Already have an account? Sign in

More from Shell Scripting in Linux

Gri-Learn · syllabus-mapped B.C.A. lessons in English, Hindi and Gujarati

Arithmetic Operations (expr, $(( ))) · Linux Operating System (LOS) (Minor-04) · Gri-Learn