Bash: The let Keyword

📅 March 18, 2024
JavaScript has the let keyword that creates a variable with scope.

Bash has the let keyword too, but it serves a different purpose.

What Does let Do?

In Bash, let is a built-in command that allows us to declare a variable and assign the result of an arithmetic expression to that variable in one step. Simply put, let is an optional shortcut.

The “long” way

#!/bin/bash

num=$(( 2 * 200 + 2))
echo "$num"

This performs a calculation and assigns it to a variable using arithmetic expansion, which is indicated with the $(( )) characters. The arithmetic we want to perform is placed within the double parentheses.

“Hey! You can also use perform arithmetic in Bash using $[ ] because this is the way I have always done it, and I am not going to change!”

Yes, this achieves the same result:

num=$[ 2 * 200 + 2 ]
echo "$num"

However, the $[ ] is deprecated in Bash, and should be avoided. Use $(( )) instead.

The shorter way using let

let num=2*200+2
echo "$num"

Did you catch that? With let, we no longer need to use $(( )). However, we must remove all spaces in the expression when used like this. This can squish the operands together and make it less readable where $(( )) allows for spaces for easier reading. Either way, the variable num contains the result of the expression.

“But I like to add whitespace to make expressions more readable.”

Easily solved. Simply enclose the expression within double quotes like this:

let num="2 * 200 + 2"  # The best way to code a let statement

In fact, we should always place the expression within double quotes to avoid potential errors. This also allows us to provide whitespace for readability

What Not to Do

Avoid using $(( )) with let because it is redundant.

let num=$(( 2 * 200 + 2 ))
echo "$num"

Yes, this works, but let already allows for an arithmetic expression, so there is no need to also include the $(( )) designed to evaluate an arithmetic expression…unless you want to add spacing for readability. If that is the case, just use $(( )) and skip let entirely or enclose the expression within double quotes when using let. Quote usage is best with let because it is considered good practice.

let Differences

let does not create a variable of an integer data type. We must use declare with the -i option to achieve that. For example,

declare -i num=$(( 2 * 200 + 2 ))

Even though Bash is an untyped shell programming language, we do have the option to create a variable designed to hold a numeric integer for those times when we need to be specific. (Note: there is no floating-point data type in Bash since Bash can only perform integer math.)

So, both of these statements achieve almost the same result:

declare -i num=$(( 2 * 200 + 2 ))  # Integer variable data type

let num="2 * 200 + 2"              # Normal Bash variable, untyped

We say almost because let does not create a variable of type integer. declare -i will do that. All let does is say, “Evaluate the following expression within the double quotes and assign that value to the variable.” The variable created by let is not typed in any way. It is a standard variable like any other.

“Why is this an issue?”

Because we cannot assign anything other than an integer to an integer variable created with declare -i. Try this experiment in Bash to see how this works:

declare -i num=$(( (RANDOM % 100) / 3))
echo $num
num='Hello, Mathman!'  # Try to assign a string to num
echo $num              # Shows 0, not Hello, Mathman
num=5005               # Assigns 5005 to num
echo $num              # Shows 5005

Output:

4
0  # Normally, this would be Hello, Mathman! but only integers are allowed
5005

The code generates a random number from 0 to 99, and then divides by 3. The result is stored in an integer variable named num. But when we try to assign a string to num, the result of num is 0, not Hello, Mathman! The variable still exists, but by using declare -i, we can only store integers in num. Nothing else.

Now, try it using let.

let num="(RANDOM % 100) / 3"
echo $num
num='Hello, Mathman!'
echo $num
num=5005
echo $num

Notice that when we use let, the RANDOM environment variable can be referenced by its name only instead of $RANDOM or ${RANDOM}.

Output:

27
Hello, Mathman!
5005

The variable num will store the string Hello, Mathman! because let creates untyped variables. This is a subtle difference but an important one since using one or the other in the wrong context can lead to time wasted debugging seemingly sound code when a variable is not storing the correct type of data in a script.

declare + let

“Can I use declare and let together?”

Yes. Try this:

declare -i let num="2 * 200 + 2"

All let does is provide an alternate way of interpreting an arithmetic expression. This evaluates the expression within double quotes and stores the value in an integer-typed variable num. Just like before, we can only assign integers to num. Anything else returns 0.

Conclusion

In short, let is a shortcut that allows us to use an alternate syntax, such as

let num="(400 + $RANDOM) % (2 + 4 - 5 + 7)"

when evaluating arithmetic expressions so we do not need to escape parentheses or use $(( )). Which technique you use really depends upon your personal preference or scripting needs. Linux is all about options.

Have fun!

 

,

  1. Leave a comment

Leave a comment