Arithmetic expressions in Bash are closely modeled on those in C, so they are very similar to those in other C-derived languages, such as C++, Java, Perl, JavaScript, C#, and PHP. One major difference is that Bash only supports integer arithmetic (whole numbers), not floating-point arithmetic (decimals and fractions); something like 3 + 4 means what you'd expect (7), but something like 3.4 + 4.5 is a syntax error. Something like 13 / 5 is fine, but performs integer division, so evaluates to 2 rather than to 2.6.
Perhaps the most common way to use arithmetic expressions is in arithmetic expansion , where the result of an arithmetic expression is used as an argument to a command. Arithmetic expansion is denoted $(( … )) . For example, this command:
prints 19 .
Another way to use arithmetic expressions is using the Unix program "expr", which was popular before Bash supported math. [ 1 ] Similar to Arithmetic expansion, this command:
prints 19 . Note that using "expr" requires an escape character "\" before the multiplication operator "*" and parentheses. Further note the spaces between each operator symbol, including the parentheses.
In addition to the familiar notations + (addition) and - (subtraction), arithmetic expressions also support * (multiplication), / (integer division, described above), % (modulo division, the "remainder" operation; for example, 11 divided by 5 is 2 remainder 1, so 11 % 5 is 1 ), and ** ("exponentiation", i.e. involution; for example, 2 4 = 16, so 2 ** 4 is 16 ).
The operators + and - , in addition to their "binary" (two-operand) senses of "addition" and "subtraction", have "unary" (one-operand) senses of "positive" and "negative". Unary + has basically no effect; unary - inverts the sign of its operand. For example, -(3*4) evaluates to -12 , and -(-(3*4)) evaluates to 12 .
Inside an arithmetic expression, shell variables can be referred to directly, without using variable expansion (that is, without the dollar sign $ ). For example, this:
prints 35 . (Note that i is evaluated first, producing 5, and then it's multiplied by 7. If we had written $i rather than i , mere string substitution would have been performed; 7 * 2+3 equals 14 + 3, that is, 17 — probably not what we want.)
The previous example shown using "expr":
prints 35 .
Shell variables can also be assigned to within an arithmetic expression. The notation for this is similar to that of regular variable assignment, but is much more flexible. For example, the previous example could be rewritten like this:
except that this sets $i to 5 rather than to 2+3 . Note that, although arithmetic expansion looks a bit like command substitution, it is not executed in a subshell; this command actually sets $i to 5 , and later commands can use the new value. (The parentheses inside the arithmetic expression are just the normal mathematical use of parentheses to control the order of operations.)
In addition to the simple assignment operator = , Bash also supports compound operators such as += , -= , *= , /= , and %= , which perform an operation followed by an assignment. For example, (( i *= 2 + 3 )) is equivalent to (( i = i * (2 + 3) )) . In each case, the expression as a whole evaluates to the new value of the variable; for example, if $i is 4 , then (( j = i *= 3 )) sets both $i and $j to 12 .
Lastly, Bash supports increment and decrement operators. The increment operator ++ increases a variable's value by 1; if it precedes the variable-name (as the "pre-increment" operator), then the expression evaluates to the variable's new value, and if it follows the variable-name (as the "post-increment" operator), then the expression evaluates to the variable's old value. For example, if $i is 4 , then (( j = ++i )) sets both $i and $j to 5 , while (( j = i++ )) sets $i to 5 and $j to 4 . The decrement operator -- is exactly the same, except that it decreases the variable's value by 1. Pre-decrement and post-decrement are completely analogous to pre-increment and post-increment.
A command can consist entirely of an arithmetic expression, using either of the following syntaxes:
Either of these commands will set $i to 5 . Both styles of command return an exit status of zero ("successful" or "true") if the expression evaluates to a non-zero value, and an exit status of one ("failure" or "false") if the expression evaluates to zero. For example, this:
will print this:
The reason for this counterintuitive behavior is that in C, zero means "false" and non-zero values (especially one) mean "true". Bash maintains that legacy inside arithmetic expressions, then translates it into the usual Bash convention at the end.
Arithmetic expressions can contain multiple sub-expressions separated by commas , . The result of the last sub-expression becomes the overall value of the full expression. For example, this:
sets $i to 2 , sets $j to 4 , and prints 8 .
The let built-in actually supports multiple expressions directly without needing a comma; therefore, the following three commands are equivalent:
Arithmetic expressions support the integer comparison operators < , > , <= (meaning ≤), >= (meaning ≥), == (meaning =), and != (meaning ≠). Each evaluates to 1 for "true" or 0 for "false".
They also support the Boolean operators && ("and"), which evaluates to 0 if either of its operands is zero, and to 1 otherwise; || ("or"), which evaluates to 1 if either of its operands is nonzero, and to 0 otherwise; and ! ("not"), which evaluates to 1 if its operand is zero, and to 0 otherwise. Aside from their use of zero to mean "false" and nonzero values to mean "true", these are just like the operators && , || , and ! that we've seen outside arithmetic expressions. Like those operators, these are "short-cutting" operators that do not evaluate their second argument if their first argument is enough to determine a result. For example, (( ( i = 0 ) && ( j = 2 ) )) will not evaluate the ( j = 2 ) part, and therefore will not set $j to 2 , because the left operand of && is zero ("false").
And they support the conditional operator b ? e1 : e2 . This operator evaluates e1 , and returns its result, if b is nonzero; otherwise, it evaluates e2 and returns its result.
These operators can be combined in complex ways:
Above, we saw one style of for-loop, that looked like this:
Bash also supports another style, modeled on the for-loops of C and related languages, using shell arithmetic:
This for-loop uses three separate arithmetic expressions, separated by semicolons ; (and not commas , — these are completely separate expressions, not just sub-expressions). The first is an initialization expression, run before the loop begins. The second is a test expression; it is evaluated before every potential loop iteration (including the first), and if it evaluates to zero ("false"), then the loop exits. The third is a counting expression; it is evaluated at the end of each loop iteration. In other words, this for-loop is exactly equivalent to this while-loop:
but, once you get used to the syntax, it makes it more clear what is going on.
In addition to regular arithmetic and Boolean operators, Bash also offers "bitwise" operators, meaning operators that operate on integers qua bit-strings rather than qua integers. If you are not already familiar with this concept, you can safely ignore these.
Just as in C, the bitwise operators are & (bitwise "and"), | (bitwise "or"), ^ (bitwise "exclusive or"), ~ (bitwise "not"), << (bitwise left-shift), and >> (bitwise right-shift), as well as &= and |= and ^= (which include assignment, just like += ).
An integer constant is expressed as an integer literal . We have already seen many of these; 34 , for example, is an integer literal denoting the number 34. All of our examples have been decimal (base ten) integer literals, which is the default; but in fact, literals may be expressed in any base in the range 2–64, using the notation base # value (with the base itself being expressed in base-ten). For example, this:
will print 12 six times. (Note that this notation only affects how an integer literal is interpreted. The result of the arithmetic expansion is still expressed in base ten, regardless.)
For bases 11 through 36, the English letters A through Z are used for digit-values 10 through 35. This is not case-sensitive. For bases 37 through 64, however, it is specifically the lowercase English letters that are used for digit-values 10 through 35, with the uppercase letters being used for digit-values 36 through 61, the at-sign @ being used for digit-value 62, and the underscore _ being used for digit-value 63. For example, 64#@A3 denotes 256259 ( 62 × 64 2 + 36 × 64 + 3 ).
There are also two special notations: prefixing a literal with 0 indicates base-eight (octal), and prefixing it with 0x or 0X indicates base-sixteen (hexadecimal). For example, 030 is equivalent to 8#30 , and 0x6F is equivalent to 16#6F .
A variable may be declared as an integer variable — that is, its "integer attribute" may be "set" — by using this syntax:
After running the above command, any subsequent assignments to n will automatically cause the right-hand side to be interpreted as an arithmetic expression. For example, this:
is more or less equivalent to this:
except that the first version's declare -i n will continue to affect later assignments as well.
In the first version, note the use of quotes around the right-hand side of the assignment. Had we written n=2 + 3 > 4 , it would have meant "run the command + with the argument 3 , passing in the environment variable n set to 2 , and redirecting standard output into the file 4 "; which is to say, setting a variable's integer attribute doesn't affect the overall parsing of assignment statements, but merely controls the interpretation of the value that is finally assigned to the variable.
We can "unset" a variable's integer attribute, turning off this behavior, by using the opposite command:
The declare built-in command has a number of other uses as well: there are a few other attributes a variable can have, and declare has a few other features besides turning attributes on and off. In addition, a few of its properties bear note:
As mentioned above, Bash shell arithmetic only supports integer arithmetic. However, external programs can often be used to obtain similar functionality for non-integer values. In particular, the common Unix utility bc is often used for this. The following command:
prints 5.6 . Needless to say, since bc is not so tightly integrated with Bash as shell arithmetic is, it is not as convenient; for example, something like this:
would, to support non-integers, become something like this:
Part of this is because we can no longer use an arithmetic for-loop; part of it is because referring to variables and assigning to variables is trickier now (since bc is not aware of the shell's variables, only its own, unrelated ones); and part of it is because bc communicates with the shell only via input and output.
Next: Grouping Commands , Previous: Looping Constructs , Up: Compound Commands [ Contents ][ Index ]
The syntax of the if command is:
The test-commands list is executed, and if its return status is zero, the consequent-commands list is executed. If test-commands returns a non-zero status, each elif list is executed in turn, and if its exit status is zero, the corresponding more-consequents is executed and the command completes. If ‘ else alternate-consequents ’ is present, and the final command in the final if or elif clause has a non-zero exit status, then alternate-consequents is executed. The return status is the exit status of the last command executed, or zero if no condition tested true.
The syntax of the case command is:
case will selectively execute the command-list corresponding to the first pattern that matches word . The match is performed according to the rules described below in Pattern Matching . If the nocasematch shell option (see the description of shopt in The Shopt Builtin ) is enabled, the match is performed without regard to the case of alphabetic characters. The ‘ | ’ is used to separate multiple patterns, and the ‘ ) ’ operator terminates a pattern list. A list of patterns and an associated command-list is known as a clause .
Each clause must be terminated with ‘ ;; ’, ‘ ;& ’, or ‘ ;;& ’. The word undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal (see Shell Parameter Expansion ) before matching is attempted. Each pattern undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, process substitution, and quote removal.
There may be an arbitrary number of case clauses, each terminated by a ‘ ;; ’, ‘ ;& ’, or ‘ ;;& ’. The first pattern that matches determines the command-list that is executed. It’s a common idiom to use ‘ * ’ as the final pattern to define the default case, since that pattern will always match.
Here is an example using case in a script that could be used to describe one interesting feature of an animal:
If the ‘ ;; ’ operator is used, no subsequent matches are attempted after the first pattern match. Using ‘ ;& ’ in place of ‘ ;; ’ causes execution to continue with the command-list associated with the next clause, if any. Using ‘ ;;& ’ in place of ‘ ;; ’ causes the shell to test the patterns in the next clause, if any, and execute any associated command-list on a successful match, continuing the case statement execution as if the pattern list had not matched.
The return status is zero if no pattern is matched. Otherwise, the return status is the exit status of the command-list executed.
The select construct allows the easy generation of menus. It has almost the same syntax as the for command:
The list of words following in is expanded, generating a list of items, and the set of expanded words is printed on the standard error output stream, each preceded by a number. If the ‘ in words ’ is omitted, the positional parameters are printed, as if ‘ in "$@" ’ had been specified. select then displays the PS3 prompt and reads a line from the standard input. If the line consists of a number corresponding to one of the displayed words, then the value of name is set to that word. If the line is empty, the words and prompt are displayed again. If EOF is read, the select command completes and returns 1. Any other value read causes name to be set to null. The line read is saved in the variable REPLY .
The commands are executed after each selection until a break command is executed, at which point the select command completes.
Here is an example that allows the user to pick a filename from the current directory, and displays the name and index of the file selected.
The arithmetic expression is evaluated according to the rules described below (see Shell Arithmetic ). The expression undergoes the same expansions as if it were within double quotes, but double quote characters in expression are not treated specially are removed. If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1.
Return a status of 0 or 1 depending on the evaluation of the conditional expression expression . Expressions are composed of the primaries described below in Bash Conditional Expressions . The words between the [[ and ]] do not undergo word splitting and filename expansion. The shell performs tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal on those words (the expansions that would occur if the words were enclosed in double quotes). Conditional operators such as ‘ -f ’ must be unquoted to be recognized as primaries.
When used with [[ , the ‘ < ’ and ‘ > ’ operators sort lexicographically using the current locale.
When the ‘ == ’ and ‘ != ’ operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching , as if the extglob shell option were enabled. The ‘ = ’ operator is identical to ‘ == ’. If the nocasematch shell option (see the description of shopt in The Shopt Builtin ) is enabled, the match is performed without regard to the case of alphabetic characters. The return value is 0 if the string matches (‘ == ’) or does not match (‘ != ’) the pattern, and 1 otherwise.
If you quote any part of the pattern, using any of the shell’s quoting mechanisms, the quoted portion is matched literally. This means every character in the quoted portion matches itself, instead of having any special pattern matching meaning.
An additional binary operator, ‘ =~ ’, is available, with the same precedence as ‘ == ’ and ‘ != ’. When you use ‘ =~ ’, the string to the right of the operator is considered a POSIX extended regular expression pattern and matched accordingly (using the POSIX regcomp and regexec interfaces usually described in regex (3)). The return value is 0 if the string matches the pattern, and 1 if it does not. If the regular expression is syntactically incorrect, the conditional expression returns 2. If the nocasematch shell option (see the description of shopt in The Shopt Builtin ) is enabled, the match is performed without regard to the case of alphabetic characters.
You can quote any part of the pattern to force the quoted portion to be matched literally instead of as a regular expression (see above). If the pattern is stored in a shell variable, quoting the variable expansion forces the entire pattern to be matched literally.
The pattern will match if it matches any part of the string. If you want to force the pattern to match the entire string, anchor the pattern using the ‘ ^ ’ and ‘ $ ’ regular expression operators.
For example, the following will match a line (stored in the shell variable line ) if there is a sequence of characters anywhere in the value consisting of any number, including zero, of characters in the space character class, immediately followed by zero or one instances of ‘ a ’, then a ‘ b ’:
That means values for line like ‘ aab ’, ‘ aaaaaab ’, ‘ xaby ’, and ‘ ab ’ will all match, as will a line containing a ‘ b ’ anywhere in its value.
If you want to match a character that’s special to the regular expression grammar (‘ ^$|[]()\.*+? ’), it has to be quoted to remove its special meaning. This means that in the pattern ‘ xxx.txt ’, the ‘ . ’ matches any character in the string (its usual regular expression meaning), but in the pattern ‘ "xxx.txt" ’, it can only match a literal ‘ . ’.
Likewise, if you want to include a character in your pattern that has a special meaning to the regular expression grammar, you must make sure it’s not quoted. If you want to anchor a pattern at the beginning or end of the string, for instance, you cannot quote the ‘ ^ ’ or ‘ $ ’ characters using any form of shell quoting.
If you want to match ‘ initial string ’ at the start of a line, the following will work:
but this will not:
because in the second example the ‘ ^ ’ is quoted and doesn’t have its usual special meaning.
It is sometimes difficult to specify a regular expression properly without using quotes, or to keep track of the quoting used by regular expressions while paying attention to shell quoting and the shell’s quote removal. Storing the regular expression in a shell variable is often a useful way to avoid problems with quoting characters that are special to the shell. For example, the following is equivalent to the pattern used above:
Shell programmers should take special care with backslashes, since backslashes are used by both the shell and regular expressions to remove the special meaning from the following character. This means that after the shell’s word expansions complete (see Shell Expansions ), any backslashes remaining in parts of the pattern that were originally not quoted can remove the special meaning of pattern characters. If any part of the pattern is quoted, the shell does its best to ensure that the regular expression treats those remaining backslashes as literal, if they appeared in a quoted portion.
The following two sets of commands are not equivalent:
The first two matches will succeed, but the second two will not, because in the second two the backslash will be part of the pattern to be matched. In the first two examples, the pattern passed to the regular expression parser is ‘ \. ’. The backslash removes the special meaning from ‘ . ’, so the literal ‘ . ’ matches. In the second two examples, the pattern passed to the regular expression parser has the backslash quoted (e.g., ‘ \\\. ’), which will not match the string, since it does not contain a backslash. If the string in the first examples were anything other than ‘ . ’, say ‘ a ’, the pattern would not match, because the quoted ‘ . ’ in the pattern loses its special meaning of matching any single character.
Bracket expressions in regular expressions can be sources of errors as well, since characters that are normally special in regular expressions lose their special meanings between brackets. However, you can use bracket expressions to match special pattern characters without quoting them, so they are sometimes useful for this purpose.
Though it might seem like a strange way to write it, the following pattern will match a ‘ . ’ in the string:
The shell performs any word expansions before passing the pattern to the regular expression functions, so you can assume that the shell’s quoting takes precedence. As noted above, the regular expression parser will interpret any unquoted backslashes remaining in the pattern after shell expansion according to its own rules. The intention is to avoid making shell programmers quote things twice as much as possible, so shell quoting should be sufficient to quote special pattern characters where that’s necessary.
The array variable BASH_REMATCH records which parts of the string matched the pattern. The element of BASH_REMATCH with index 0 contains the portion of the string matching the entire regular expression. Substrings matched by parenthesized subexpressions within the regular expression are saved in the remaining BASH_REMATCH indices. The element of BASH_REMATCH with index n is the portion of the string matching the n th parenthesized subexpression.
Bash sets BASH_REMATCH in the global scope; declaring it as a local variable will lead to unexpected results.
Expressions may be combined using the following operators, listed in decreasing order of precedence:
Returns the value of expression . This may be used to override the normal precedence of operators.
True if expression is false.
True if both expression1 and expression2 are true.
True if either expression1 or expression2 is true.
The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression.
Find centralized, trusted content and collaborate around the technologies you use most.
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Get early access and see previews of new features.
I have no idea why the compound array initialization does not work for me.
minimal example:
with 2 additional blank lines.
Fieldwise initialization works:
I have tried every possible combination of braces, quotes and "declare -a".
Could it be related to my bash version? I'm running version 4.1.2(1).
The problem is, you are not using bash. Shebang doesn't matter if you run your script throught sh . Try bash instead.
I tried the below code and its working fine for me. Using bash 3.2.39(1)-release
Output for this was
For me with your code it was giving an error
I would suspect there is some quoting going on in your first example using compound assignments. Using this modified test script:
I get the following output:
If you quote the assignment, it becomes a simple variable assignment; a simple mistake to make that is easily overlooked.
Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more
Post as a guest.
Required, but never shown
By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .
COMMENTS
Using the multiple variable assignment technique in Bash scripts can make our code look compact and give us the benefit of better performance, particularly when we want to assign multiple variables by the output of expensive command execution. For example, let's say we want to assign seven variables - the calendar week number, year, month ...
In Bash, the double parentheses set up an arithmetic context (in which dollar signs are mostly optional, by the way) for a comparison (also used in for ((i=0; i<=10; i++)) and $(()) arithmetic expansion) and is used to distinguish the sequence from a set of single parentheses which creates a subshell. This, for example, executes the command ...
In bash programming, assignment operators are like tools that let you give values to things. For example, you can tell the computer that "x equals 5" or "name equals tecadmin". ... Compound Assignment Operators. The compound assignment operators combination of performing some operation and then assign value to variable in a single ...
6.4 Bash Conditional Expressions. Conditional expressions are used by the [[ compound command (see Conditional Constructs) and the test and [ builtin commands (see Bourne Shell Builtins). The test and [ commands determine their behavior based on the number of arguments; see the descriptions of those commands for any other command-specific actions.
The preferable way to do math in Bash is to use shell arithmetic expansion. The built-in capability evaluates math expressions and returns the result. The syntax for arithmetic expansions is: $((expression)) The syntax consists of: Compound notation (()) which evaluates the expression. The variable operator $ to store the result.
In Bash, the += operator is a compound assignment operator that allows you to add (concatenate) a string or value to the end of an existing variable's value. It's commonly used for building or modifying strings dynamically in scripts. What is binary operator in Bash? A binary operator in Bash is an operator that works on two operands or
Compound commands are the shell programming language constructs. Each construct begins with a reserved word or control operator and is terminated by a corresponding reserved word or operator. Any redirections (see Redirections) associated with a compound command apply to all commands within that compound command unless explicitly overridden. In ...
Assignment to BASH_ARGV0 causes the value assigned to also be assigned to $0. If BASH_ARGV0 is ... The += operator will append to an array variable when assigning using the compound assignment syntax; see PARAMETERS above. Any element of an array may be referenced using ${name [subscript]}. The braces are required to avoid conflicts with ...
It's time-consuming and annoying to run multiple commands one-by-one. To prevent such situations and obtain the expected result, we can combine and execute multiple commands in the command line. 3. Concatenate Commands With ";". The ";" operator executes all commands regardless of whether the previous ones failed or not.
As WP says, $(()) can only contain arithmetic expressions and therefore, a general ternary assignment doesn't exist in Bash. - zakmck. Commented Apr 10, 2023 at 18:49. @zakmck i think you should check again. try the code in the example. - mikeserv. Commented Sep 24, 2023 at 2:07.
The '+=' operator will append to an array variable when assigning using the compound assignment syntax; see Shell Parameters above. ... and bash will create an array if necessary. An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. It is possible to obtain the keys (indices) ...
Next: Aliases, Previous: Bash Conditional Expressions, Up: Bash Features 6.5 Shell Arithmetic The shell allows arithmetic expressions to be evaluated, as one of the shell expansions or by using the (( compound command, the let builtin, or the -i option to the declare builtin.
The notation for this is similar to that of regular variable assignment, but is much more flexible. For example, the previous example could be rewritten like this: ... Bash also supports compound operators such as +=, -=, *=, /=, and %=, which perform an operation followed by an assignment.
1.1 What is Bash? Bash is the shell, or command language interpreter, for the GNU operating system. The name is an acronym for the 'Bourne-Again SHell', a pun on Stephen Bourne, the author of the direct ancestor of the current Unix shell sh, which appeared in the Seventh Edition Bell Labs Research version of Unix. Bash is largely compatible with sh and incorporates useful features from the ...
3.2.5.3 Grouping Commands. Bash provides two ways to group a list of commands to be executed as a unit. When commands are grouped, redirections may be applied to the entire command list. For example, the output of all the commands in the list may be redirected to a single stream. Placing a list of commands between parentheses forces the shell ...
3.2.5.2 Conditional Constructs. The syntax of the if command is: consequent-commands; more-consequents;] The test-commands list is executed, and if its return status is zero, the consequent-commands list is executed. If test-commands returns a non-zero status, each elif list is executed in turn, and if its exit status is zero, the corresponding ...
In BASH and other Bourne type shells, the if command merely runs the command, and if the command returns an exit code of 0, it executes the commands in the if clause. If the command does not return an exit code of 0, it skips the commands in the if clause and executes the commands in the else clause if it exists.. Thus, this is also valid: if sleep 2 then echo "That was a good nap!"
Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers; Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand; OverflowAI GenAI features for Teams; OverflowAPI Train & fine-tune LLMs; Labs The future of collective knowledge sharing; About the company Visit the blog