Published at
Updated at
Reading time
3min
This post is part of my Today I learned series in which I share all my web development learnings.

I was kneedeep into CI/CD scripting, when I hit a wall. You can't just do simple math like adding or subtracting integers in a shell environment? How could I have not discovered this fact before?

As it turns out, simple operations like summing and subtracting two variables need some serious shell knowledge.

Here's the problem.

#!/bin/sh

a=1
b=2
c=$a+$b
echo $c # 1+2

When evaluating c, $a and $b are resolved to their values (1 and 2), but the + is treated as a string. All three parts are strings, and now the result is 1+2. Ufff.

After researching this problem, I learned that there are multiple ways to do math in shell environments. Let's have a look!

The expr command

Let's start with my first Google result โ€” expr.

#!/bin/sh

a=1
b=2
c=`expr $a + $b`

echo $c #3

Backticks and expr worked, but Shellcheck wasn't happy about it.

Editor error: Use $(...) notation instead of legacy backticks `...`.

Shellcheck's slogan is that it "finds bugs in your shell scripts". And this couldn't be more true. The linter is one of these invaluable tools that shows me the problems in my lousy code.

Install it in your editor now, and thank me later. ๐Ÿ˜‰

I didn't spend time on "legacy backticks" and moved on quickly.

The let or declare builtins

I learned that let and declare let you evaluate arithmetic expressions in a single line. Fancy!

#!/bin/sh

a=1
b=2
let c=a+b
declare -i d=a+b

echo $c # 3
echo $d # 3

The let and declare approach also worked fine, but I didn't find these one-liners good to read.

And more importantly, again, Shellcheck complained. let isn't available in sh shells, and there seems to be a better option in bash.

In POSIX sh, 'let' is undefined.

Instead of 'let expr', prefer (( expr )).

Arithmetic Expansion ($(( )))

So here's the better and final option: the winner is arithmetic expansion ($(( ))). It's a fancy syntax to mark parts of your shell code as an arithmetic operation. In plain English, anything between the parentheses is considered math. ๐Ÿ’ช

#!/bin/sh

a=1
b=2
c=$((a+b))

echo $c # 3

Again, this script worked fine, but this time Shellcheck was also happy about it. Success!

Let's look at two quick arithmetic expansion facts I discovered.

Many online examples show variables with the $ character. It's optional when you want to perform an arithmetic operation.

#!/bin/sh

a=1
b=2
c=$((a+b))
d=$(($a+$b))

echo $c # 3
echo $d # 3

Also, variables that don't represent an integer are ignored in your calculations. They don't throw an error.

#!/bin/sh

a=hello
b=3
c=$((a+b))
echo $c # 3

And that's it! If you want to do math in your shell scripts, $(( )) is your friend.

But that's not all!

Sure, I learned how to add numbers in a shell environment today, but can I now say I know what I'm doing when writing these scripts? Absolutely not.

My Google research unveiled all these different approaches. How would I have known what's best? I'd have used the first solution that worked. Luckily, Shellcheck showed me the way.

So there's another hidden lesson here today: linters are great software. Use them!

Was this TIL post helpful?
Yes? Cool! You might want to check out Web Weekly for more quick learnings. The last edition went out 13 days ago.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles