2024-04-02 21:19:20 +02:00
|
|
|
---
|
|
|
|
tags:
|
|
|
|
- bash
|
|
|
|
- shell
|
|
|
|
- scripting
|
|
|
|
- math
|
|
|
|
- arithmetic
|
|
|
|
- C
|
|
|
|
- calculation
|
|
|
|
- integer
|
|
|
|
---
|
2023-07-05 11:43:35 +02:00
|
|
|
|
2024-04-02 21:19:20 +02:00
|
|
|
# Arithmetic expressions
|
2023-07-05 11:43:35 +02:00
|
|
|
|
|
|
|
Arithmetic expressions are used in several situations:
|
|
|
|
|
2024-01-29 02:01:50 +01:00
|
|
|
- [arithmetic evaluation command](../syntax/ccmd/arithmetic_eval.md)
|
|
|
|
- [arithmetic expansion](../syntax/expansion/arith.md)
|
|
|
|
- [substring parameter expansion](../syntax/pe.md#substring_expansion)
|
|
|
|
- [the `let` builtin command](../commands/builtin/let.md)
|
|
|
|
- [C-style for loop](../syntax/ccmd/c_for.md)
|
|
|
|
- [array indexing](../syntax/arrays.md)
|
|
|
|
- [conditional expressions](../syntax/ccmd/conditional_expression.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- Assignment statements, and arguments to declaration commands of
|
|
|
|
variables with the integer attribute.
|
|
|
|
|
|
|
|
These expressions are evaluated following some rules described below.
|
|
|
|
The operators and rules of arithmetic expressions are mainly derived
|
|
|
|
from the C programming language.
|
|
|
|
|
|
|
|
This article describes the theory of the used syntax and the behaviour.
|
|
|
|
To get practical examples without big explanations, see [this page on
|
2024-03-30 19:22:45 +01:00
|
|
|
Greg's
|
2023-07-05 11:43:35 +02:00
|
|
|
wiki](http://mywiki.wooledge.org/BashGuide/CompoundCommands#Arithmetic_Evaluation).
|
|
|
|
|
|
|
|
## Constants
|
|
|
|
|
|
|
|
Mathematical constants are simply fixed values you write: `1`, `3567`,
|
|
|
|
or `4326`. Bash interprets some notations specially:
|
|
|
|
|
|
|
|
- `0...` (leading zero) is interpreted as an **octal** value
|
|
|
|
- `0x...` is interpreted as a **hex** value
|
|
|
|
- `0X...` also interpreted as a **hex**
|
|
|
|
- `<BASE>#...` is interpreted as a number according to the **specified
|
|
|
|
base** `<BASE>`, e.g., `2#00111011` (see below)
|
|
|
|
|
|
|
|
If you have a constant set in a variable, like,
|
|
|
|
|
|
|
|
x=03254
|
|
|
|
|
|
|
|
this is interpreted as an octal value. If you want it to be interpreted
|
|
|
|
as a decimal value, you need to expand the parameter and specify base
|
|
|
|
10:
|
|
|
|
|
|
|
|
# this is interpreted as a decimal:
|
|
|
|
echo $(( 10#$x ))
|
|
|
|
|
|
|
|
# this is interpreted as an octal:
|
|
|
|
echo $(( x ))
|
|
|
|
|
|
|
|
# this is an invalid digit for base 10 (the "x")...:
|
|
|
|
echo $(( 10#x ))
|
|
|
|
|
|
|
|
## Different bases
|
|
|
|
|
|
|
|
For a constant, the base can be specified using the form
|
|
|
|
|
|
|
|
<BASE>#<DIGITS...>
|
|
|
|
|
|
|
|
Regardless of the specified base, the arithmetic expressions will, if
|
|
|
|
ever displayed, be **displayed in decimal**!
|
|
|
|
|
|
|
|
When no base is specified, the base 10 (decimal) is assumed, except when
|
|
|
|
the prefixes as mentioned above (octals, hexadecimals) are present. The
|
|
|
|
specified base can range from 2 to 64. To represent digits in a
|
|
|
|
specified base greater than 10, characters other than 0 to 9 are needed
|
2024-04-01 06:10:32 +02:00
|
|
|
(in this order, low => high):
|
2023-07-05 11:43:35 +02:00
|
|
|
|
|
|
|
- `0 ... 9`
|
|
|
|
- `a ... z`
|
|
|
|
- `A ... Z`
|
|
|
|
- `@`
|
|
|
|
- `_`
|
|
|
|
|
2024-03-30 19:22:45 +01:00
|
|
|
Let's quickly invent a new number system with base 43 to show what I
|
2023-07-05 11:43:35 +02:00
|
|
|
mean:
|
|
|
|
|
|
|
|
$ echo $((43#1))
|
|
|
|
1
|
|
|
|
|
|
|
|
$ echo $((43#a))
|
|
|
|
10
|
|
|
|
|
|
|
|
$echo $((43#A))
|
|
|
|
36
|
|
|
|
|
|
|
|
$ echo $((43#G))
|
|
|
|
42
|
|
|
|
|
|
|
|
$ echo $((43#H))
|
|
|
|
bash: 43#H: value too great for base (error token is "43#H")
|
|
|
|
|
|
|
|
If you have no clue what a base is and why there might be other bases,
|
2024-03-30 20:09:26 +01:00
|
|
|
and what numbers are and how they are built, then you don't need
|
2023-07-05 11:43:35 +02:00
|
|
|
different bases.
|
|
|
|
|
|
|
|
If you want to convert between the usual bases (octal, decimal, hex),
|
2024-01-29 02:01:50 +01:00
|
|
|
use [the printf command](../commands/builtin/printf.md) and its format
|
2023-07-05 11:43:35 +02:00
|
|
|
strings.
|
|
|
|
|
|
|
|
## Shell variables
|
|
|
|
|
|
|
|
Shell variables can of course be used as operands, even when the integer
|
|
|
|
attribute is not turned on (by `declare -i <NAME>`). If the variable is
|
|
|
|
empty (null) or unset, its reference evaluates to 0. If the variable
|
2024-03-30 20:09:26 +01:00
|
|
|
doesn't hold a value that looks like a valid expression (numbers or
|
2023-07-05 11:43:35 +02:00
|
|
|
operations), the expression is re-used to reference, for example, the
|
|
|
|
named parameters, e.g.:
|
|
|
|
|
|
|
|
test=string
|
|
|
|
string=3
|
|
|
|
|
|
|
|
echo $((test))
|
|
|
|
# will output "3"!
|
|
|
|
|
|
|
|
Of course, in the end, when it finally evaluates to something that is
|
|
|
|
**not** a valid arithmetic expression (newlines, ordinary text, \...)
|
|
|
|
then you\'ll get an error.
|
|
|
|
|
|
|
|
When variables are referenced, the notation `1 + $X` is equivalent to
|
|
|
|
the notation `1 + X`, both are allowed.
|
|
|
|
|
|
|
|
When variables are referenced like `$X`, the rules of [parameter
|
2024-01-29 02:01:50 +01:00
|
|
|
expansion](../syntax/pe.md) apply and are performed **before** the expression
|
2023-07-05 11:43:35 +02:00
|
|
|
is evaluated. Thus, a construct like `${MYSTRING:4:3}` is valid inside
|
|
|
|
an arithmetic expression.
|
|
|
|
|
|
|
|
## Truth
|
|
|
|
|
|
|
|
Unlike command exit and return codes, arithmetic expressions evaluate to
|
|
|
|
logical \"true\" when they are not 0. When they are 0, they evaluate to
|
|
|
|
\"false\". The [arithmetic evaluation compound
|
2024-01-29 02:01:50 +01:00
|
|
|
command](../syntax/ccmd/arithmetic_eval.md) reverses the \"truth\" of an
|
2023-07-05 11:43:35 +02:00
|
|
|
arithmetic expression to match the \"truth\" of command exit codes:
|
|
|
|
|
|
|
|
- if the arithmetic expression brings up a value not 0 (arithmetic
|
|
|
|
true), it returns 0 (shell true)
|
|
|
|
- if the arithmetic expression evaluates to 0 (arithmetic false), it
|
|
|
|
returns 1 (shell false)
|
|
|
|
|
|
|
|
That means, the following `if`-clause will execute the `else`-thread:
|
|
|
|
|
|
|
|
if ((0)); then
|
|
|
|
echo "true"
|
|
|
|
else
|
|
|
|
echo "false"
|
|
|
|
fi
|
|
|
|
|
|
|
|
## Operators
|
|
|
|
|
|
|
|
### Assignment
|
|
|
|
|
|
|
|
Operator Description
|
|
|
|
--------------------- ----------------------------------------------------------------------------------------------------
|
|
|
|
`<ID> = <EXPR>` normal assignment
|
2024-01-29 02:01:50 +01:00
|
|
|
`<ID> *= <EXPR>` equivalent to `<ID> = <ID> * <EXPR>`, see [calculation operators](../syntax/arith_expr.md#calculations)
|
|
|
|
`<ID> /= <EXPR>` equivalent to `<ID> = <ID> / <EXPR>`, see [calculation operators](../syntax/arith_expr.md#calculations)
|
|
|
|
`<ID> %= <EXPR>` equivalent to `<ID> = <ID> % <EXPR>`, see [calculation operators](../syntax/arith_expr.md#calculations)
|
|
|
|
`<ID> += <EXPR>` equivalent to `<ID> = <ID> + <EXPR>`, see [calculation operators](../syntax/arith_expr.md#calculations)
|
|
|
|
`<ID> -= <EXPR>` equivalent to `<ID> = <ID> - <EXPR>`, see [calculation operators](../syntax/arith_expr.md#calculations)
|
|
|
|
`<ID> <<= <NUMBER>` equivalent to `<ID> = <ID> << <NUMBER>`, see [bit operations](../syntax/arith_expr.md#bit_operations)
|
|
|
|
`<ID> >>= <NUMBER>` equivalent to `<ID> = <ID> >> <NUMBER>`, see [bit operations](../syntax/arith_expr.md#bit_operations)
|
|
|
|
`<ID> &= <EXPR>` equivalent to `<ID> = <ID> & <EXPR>`, see [bit operations](../syntax/arith_expr.md#bit_operations)
|
|
|
|
`<ID> ^= <EXPR>` equivalent to `<ID> = <ID> ^ <EXPR>`, see [bit operations](../syntax/arith_expr.md#bit_operations)
|
|
|
|
`<ID> |= <EXPR>` equivalent to `<ID> = <ID> | <EXPR>`, see [bit operations](../syntax/arith_expr.md#bit_operations)
|
2023-07-05 11:43:35 +02:00
|
|
|
|
|
|
|
### Calculations
|
|
|
|
|
|
|
|
Operator Description
|
|
|
|
---------- --------------------
|
|
|
|
`*` multiplication
|
|
|
|
`/` division
|
|
|
|
`%` remainder (modulo)
|
|
|
|
`+` addition
|
|
|
|
`-` subtraction
|
|
|
|
`**` exponentiation
|
|
|
|
|
|
|
|
### Comparisons
|
|
|
|
|
|
|
|
Operator Description
|
|
|
|
---------- -----------------------------------
|
|
|
|
`<` comparison: less than
|
|
|
|
`>` comparison: greater than
|
|
|
|
`<=` comparison: less than or equal
|
|
|
|
`>=` comparison: greater than or equal
|
|
|
|
`==` equality
|
|
|
|
`!=` inequality
|
|
|
|
|
|
|
|
### Bit operations
|
|
|
|
|
|
|
|
Operator Description
|
|
|
|
---------- ----------------------------
|
|
|
|
`~` bitwise negation
|
|
|
|
`<<` bitwise shifting (left)
|
|
|
|
`>>` bitwise shifting (right)
|
|
|
|
`&` bitwise AND
|
|
|
|
`^` bitwise exclusive OR (XOR)
|
|
|
|
`|` bitwise OR
|
|
|
|
|
|
|
|
### Logical
|
|
|
|
|
|
|
|
Operator Description
|
|
|
|
---------- ------------------
|
|
|
|
`!` logical negation
|
|
|
|
`&&` logical AND
|
|
|
|
`||` logical OR
|
|
|
|
|
|
|
|
### Misc
|
|
|
|
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
Operator Description
|
|
|
|
---------------------------- --------------------------------------------------------------------
|
|
|
|
`id++` **post-increment** of the variable `id` (not required by POSIX(r))
|
|
|
|
|
|
|
|
`id--` **post-decrement** of the variable `id` (not required by POSIX(r))
|
|
|
|
|
|
|
|
`++id` **pre-increment** of the variable `id` (not required by POSIX(r))
|
|
|
|
|
|
|
|
`--id` **pre-decrement** of the variable `id` (not required by POSIX(r))
|
|
|
|
|
|
|
|
`+` unary plus
|
|
|
|
|
|
|
|
`-` unary minus
|
|
|
|
|
|
|
|
`<EXPR> ? <EXPR> : <EXPR>` conditional (ternary) operator\
|
2024-04-01 06:10:32 +02:00
|
|
|
<condition> ? <result-if-true> : <result-if-false>
|
2023-07-05 11:43:35 +02:00
|
|
|
|
|
|
|
`<EXPR> , <EXPR>` expression list
|
|
|
|
|
|
|
|
`( <EXPR> )` subexpression (to force precedence)
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
## Precedence
|
|
|
|
|
2024-04-01 06:10:32 +02:00
|
|
|
The operator precedence is as follows (highest -> lowest):
|
2023-07-05 11:43:35 +02:00
|
|
|
|
|
|
|
- Postfix (`id++`, `id--`)
|
|
|
|
- Prefix (`++id`, `--id`)
|
|
|
|
- Unary minus and plus (`-`, `+`)
|
|
|
|
- Logical and bitwise negation (`!`, `~`)
|
|
|
|
- Exponentiation (`**`)
|
|
|
|
- Multiplication, division, remainder (`*`, `/`, `%`)
|
|
|
|
- Addition, subtraction (`+`, `-`)
|
|
|
|
- Bitwise shifts (`<<`, `>>`)
|
|
|
|
- Comparison (`<`, `>`, `<=`, `>=`)
|
|
|
|
- (In-)equality (`==`, `!=`)
|
|
|
|
- Bitwise AND (`&`)
|
|
|
|
- Bitwise XOR (`^`)
|
|
|
|
- Bitwise OR (`|`)
|
|
|
|
- Logical AND (`&&`)
|
|
|
|
- Logical OR (`||`)
|
|
|
|
- Ternary operator (`<EXPR> ? <EXPR> : <EXPR>`)
|
|
|
|
- Assignments (`=`, `*=`, `/=`, `%=`, `+=`, `-=`, `<<=`, `>>=`, `&=`,
|
|
|
|
`^=`, `|=`)
|
|
|
|
- Expression list operator (`<EXPR> , <EXPR>`)
|
|
|
|
|
|
|
|
The precedence can be adjusted using subexpressions of the form
|
|
|
|
`( <EXPR> )` at any time. These subexpressions are always evaluated
|
|
|
|
first.
|
|
|
|
|
|
|
|
## Arithmetic expressions and return codes
|
|
|
|
|
2024-03-30 19:22:45 +01:00
|
|
|
Bash's overall language construct is based on exit codes or return
|
2023-07-05 11:43:35 +02:00
|
|
|
codes of commands or functions to be executed. `if` statements, `while`
|
|
|
|
loops, etc., they all take the return codes of commands as conditions.
|
|
|
|
|
|
|
|
Now the problem is: The return codes (0 means \"TRUE\" or \"SUCCESS\",
|
2024-03-30 20:09:26 +01:00
|
|
|
not 0 means \"FALSE\" or \"FAILURE\") don't correspond to the meaning
|
2023-07-05 11:43:35 +02:00
|
|
|
of the result of an arithmetic expression (0 means \"FALSE\", not 0
|
|
|
|
means \"TRUE\").
|
|
|
|
|
2024-03-30 19:22:45 +01:00
|
|
|
That's why all commands and keywords that do arithmetic operations
|
2023-07-05 11:43:35 +02:00
|
|
|
attempt to **translate** the arithmetical meaning into an equivalent
|
|
|
|
return code. This simply means:
|
|
|
|
|
|
|
|
- if the arithmetic operation evaluates to 0 (\"FALSE\"), the return
|
|
|
|
code is not 0 (\"FAILURE\")
|
|
|
|
- if the arithmetic operation evaluates to 1 (\"TRUE\"), the return
|
|
|
|
code is 0 (\"SUCCESS\")
|
|
|
|
|
|
|
|
This way, you can easily use arithmetic expressions (along with the
|
|
|
|
commands or keywords that operate them) as conditions for `if`, `while`
|
|
|
|
and all the others, including `set -e` for autoexit on error:
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
MY_TEST_FLAG=0
|
|
|
|
|
|
|
|
if ((MY_TEST_FLAG)); then
|
|
|
|
echo "MY_TEST_FLAG is ON"
|
|
|
|
else
|
|
|
|
echo "MY_TEST_FLAG is OFF"
|
|
|
|
fi
|
|
|
|
```
|
|
|
|
|
2024-04-01 06:10:32 +02:00
|
|
|
<WRAP center round important> Beware that `set -e` can change the
|
2023-07-05 11:43:35 +02:00
|
|
|
runtime behavior of scripts. For example,
|
|
|
|
|
|
|
|
This non-equivalence of code behavior deserves some attention. Consider
|
|
|
|
what happens if v happens to be zero in the expression below:
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
((v += 0))
|
|
|
|
echo $?
|
|
|
|
```
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
(\"FAILURE\")
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
v=$((v + 0))
|
|
|
|
echo $?
|
|
|
|
```
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
(\"SUCCESS\")
|
|
|
|
|
|
|
|
The return code behavior is not equivalent to the arithmetic behavior,
|
|
|
|
as has been noted.
|
|
|
|
|
|
|
|
A workaround is to use a list operation that returns True, or use the
|
|
|
|
second assignment style.
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
((v += 0)) || :
|
|
|
|
echo $?
|
|
|
|
```
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
(\"SUCCESS\")
|
|
|
|
|
|
|
|
This change in code behavior was discovered once the script was run
|
2024-04-01 06:10:32 +02:00
|
|
|
under set -e. </WRAP>
|
2023-07-05 11:43:35 +02:00
|
|
|
|
|
|
|
## Arithmetic expressions in Bash
|
|
|
|
|
2024-01-29 02:01:50 +01:00
|
|
|
- [The C-style for-loop](../syntax/ccmd/c_for.md)
|
|
|
|
- [Arithmetic expansion](../syntax/expansion/arith.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- [Arithmetic evaluation compound
|
2024-01-29 02:01:50 +01:00
|
|
|
command](../syntax/ccmd/arithmetic_eval.md)
|
|
|
|
- [The \"let\" builtin command](../commands/builtin/let.md)
|