# Bash let builtin command

- About let
- Syntax
- Other ways to evaluate arithmetic
- Examples
- Related commands
- Bash builtin commands index
- Linux and Unix commands help

▸ Related commands

▸ Bash builtins index

▸ Linux & Unix commands help

## 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

letarg[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

## Related commands

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