Bash let builtin command

Updated: 12/29/2017 by Computer Hope

About let

let is a builtin command of the Bash shell which evaluates arithmetic expressions.

Using let is similar to enclosing an arithmetic expression in double parentheses, for instance:

(( expr ))

However, unlike (( ... )), which is a compound command, let is a builtin command. As such, just like a simple command, its individual arguments are subject to expansion by bash. For instance, let arguments will undergo globbing, pathname expansion, and word splitting unless you enclose the individual arguments in double quotes.

In the majority of situations, it's preferable to use double parentheses to evaluate arithmetic expressions. However, it's important to understand how let is different, and use it where appropriate.

Like all simple commands, let has its own environment. Variables used in expressions have scope local to the command. So, for instance, an argument to let will not be aware of other shell variables, unless they are exported.

The exception is whenever let evaluates an expression that explicitly sets a variable's value. In that case, that variable's value persists in the current shell. (If this sounds a little convoluted, that's because it is. See below for examples.)

Syntax

let arg [arg ...]

Description

let evaluates each argument, arg, as a math expression. Arguments are evaluated left to right.

All numbers are represented internally as fixed-width integers. (Bash does not support floating-point arithmetic.)

No overflow checking is performed, so operations on very large integers may produce an unexpected result, without causing an error.

Division by zero is detected, however, and causes an error.

Arithmetic operators

When evaluating an expression, let interprets the following mathematical operators, and performs the corresponding operation. In the table below, operators are listed row-by-row in order of decreasing precedence. Operators listed on the same row are of equal precedence.

Operator Operation
var++, var-- Post-increment (++), Post-decrement (--).
Interpret the value of integer variable var and then add or subtract one (1) to it.
++var, --var Pre-increment (++), Pre-decrement (--).
Add or subtract one (1) to the value of integer variable var, and then interpret the value.
-expr, +expr Unary minus, Unary plus.
Unary minus returns the value of the expression expr it precedes, as if it had been multiplied by negative one (-1). Unary plus returns the expression expr unchanged, as if it had been multiplied by one (1).
!, ~ Logical negation, Bitwise negation.
Logical negation returns false if its operand is true, and true if the operand is false.
Bitwise negation flips the bits in the binary representation of the numeric operand.
** Exponentiation.
*, /, % Multiplication, Division, Remainder (modulo).
+, - Addition, Subtraction.
<<, >> Bitwise shift left, bitwise shift right.
<=,>=,<,> Comparison: Less than or equal to, Greater than or equal to, Less than, Greater than.
==, != Equality, Inequality.
Equality returns true if its operands are equal, false otherwise. Inequality returns true if its operands are not equal, false otherwise.
& Bitwise AND.
The corresponding binary digits of both operands are multiplied to produce a result; for any given digit, the resulting digit is 1 if and only if the corresponding digit in both operands is also 1.
^ Bitwise XOR (eXclusive OR).
A binary digit of the result is 1 if and only if the corresponding digits of the operands differ. For instance, if the first binary digit of the first operand is 1, and the first digit of the second operand is 0, the first digit of the result is 1.
| Bitwise OR.
If either of the corresponding digits in the operands is 1, that digit in the result will also be 1.
&& Logical AND.
Returns true if both of the operands are true.
|| Logical OR.
Returns true if either of the operands is true.
expr1 ? expr2 : expr3 Conditional (ternary) operator.
If expr1 is true, return expr2. If expr1 is false, return expr3.
=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= Assignment.
Assign the value of the expression that follows the operator, to the variable that precedes it. If an operator prefixes the equals sign, that operation is performed prior to assignment.
For instance, let "var += 5" is equivalent to let "var = var + 5". The assignment operation itself evaluates to the value assigned.

Exit status

If the rightmost argument provided to let evaluates to zero (arithmetically false), the exit status is 1 (FALSE exit status).

If the rightmost argument provided to let evaluates to non-zero (arithmetically true), the exit status is 0 (TRUE exit status).

Other ways to evaluate arithmetic

Before we start using let, let's look at other ways to do similar things in bash. Then we'll look at how let is a little different.

To begin, set the value of a variable. You can do this in bash without let, using the form varname=value. For instance:

myvar=5

Notice that there is no space before or after the equals sign. If you put a space before the =, bash will assume myvar is a command name. For instance:

myvar = 5
myvar: command not found

Similarly, you'll get an error if you put a space after the equals sign:

myvar= 5
5: command not found

Bash interprets the above command as: "With myvar equaling nothing, run the command 5." So when assigning variables this way in bash, make sure not to use spaces around the equals sign.

By default, bash variables are "typeless" — they don't have an inherent data type. For example, you can assign an integer or a string value to a typeless variable. So if we try to assign "5 + 5" to myvar, it will be assigned literally, as a string, and no math will be performed on it.

myvar="5 + 5"; echo $myvar
5 + 5

If you'd like, however, you can declare a variable as integer type using the declare builtin command. Using declare -i sets the "integer" attribute for your variable, which enables arithmetic evaluation when assigning value.

declare -i myvar; myvar="5 + 5"; echo $myvar
10

Before we continue, let's unset the integer attribute, making the variable typeless again. You can do this by using a plus sign, rather than a dash, in front of the option letter:

declare +i myvar

Another way to perform arithmetic evaluation of an expression is to enclose it in double parentheses:

(( myvar = 6 + 6 )); echo $myvar
12

Notice that myvar is inside the double parentheses: the variable assignment is part of the expression. Also, notice that it's OK to have spaces before and after the equals sign in an arithmetic expression.

To return the value of an arithmetic expression directly, so that its result can be used as part of a larger statement, prefix the double parentheses with a dollar sign ("$"), like this:

echo $(( 7 + 7 ))
14

Using the dollar sign, the final result of the expression is returned as the value. Using this syntax, we don't need to set a variable to use the value later.

Also, note that double parentheses expressions can be nested:

echo $(( myvar = 7 + $(( vartwo = 4 + 4 )) ))
15
echo $vartwo
8

Now let's perform some example commands using let.

Examples

let "myvar = 5"; echo $myvar

Set the variable myvar to the value 5, then echo the value of myvar to the terminal. Output:

5
let "varone = 1" "vartwo = varone++"; echo $varone, $vartwo

Set varone to 1, set vartwo to the value of varone, then increment the value of varone by one. Output:

2, 1
let "varone = 1" "vartwo = ++varone"; echo $varone, $vartwo

Set varone to 1, increment the value of varone by one, then set the value of vartwo to the value of varone. Output:

2, 2
let "myvar = 48 % 5"; echo $myvar

Set myvar to the remainder of 48 divided by 5 (which is 3). Output:

3
let "myvar = 16 << 2"; echo $myvar

Set myvar to the number 16, bitshifted left twice (which gives the same result as multiplying it by 2, twice). Output:

64
let "myvar = 16 >> 2"; echo $myvar

Set myvar to the number 16, bitshifted right twice (which gives the same result as dividing it by 2, twice). Output:

4
let "myvar = 5, myvar *= 2"; echo $myvar

Set myvar to 5, then set myvar to its own value multiplied by 2. Notice that in this example, sequential statements are separated by a comma. Output:

10
bar=5 let "foo = bar"; echo $foo, $bar

Set bar to 5, then set the value of bar to the value of foo. When bash processes the next command ("echo $foo, $bar") it knows about foo because its value was set in the expression, but it doesn't know about bar because bar's value was local to the previous command. Output:

5, 
bar=5 let "foo = bar, bar++"; echo $foo, $bar

Similar to the above command, but this time, let changes the value of bar by incrementing it, so bar's scope becomes the current shell, and the echo command is aware of its value. Output:

5, 6

eval — Evaluate arguments, and execute them as a command.