The book “Learning the bash Shell” 3rd ed. by Cameron Newham and Bill Rosenblatt has at page 181 a picture describing the command-line processing of bash shell. That picture shows that Command substitution is performed before Arithmetic substitution (sic). The bash man page, though, reports a different order: “The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and pathname expansion.” Is the book wrong? If it is, can you please provide an example demonstrating it?
2 Answers
The official documentation is right (but mind the subtle difference between "," and ";" in there):
Command substitution $()
/``
and arithmetic substitution $(())
have the same precedence. Whatever comes first when reading left to right, is expanded first.
You can confirm this with a test. Here, we use the built-in variable $SECONDS
, which contains the time in seconds since bash started.
#! /bin/bash
echo "$(sleep 1; echo "command $SECONDS"; sleep 1), arithmetic $((SECONDS))"
echo "arithmetic $((SECONDS)), $(sleep 1; echo "command $SECONDS"; sleep 1)"
This prints
command 1, arithmetic 2
arithmetic 2, command 3

- 25,550
- 3
- 32
- 54
-
For another example, try `export x=1; echo "cmd:$(printenv x), arith:$((++x)), cmd:$(printenv x), arith:$((++x)), cmd:$(printenv x)"` -- here, it's the arithmetic expansions changing the variable, and you can see the command substitutions being affected by the changes as it works through them from left to right. – Gordon Davisson Aug 05 '23 at 21:06
1st of all, according to the official bash documentation The order is as follows:
Expansion is performed on the command line after it has been split into tokens. There are seven kinds of expansion performed:
- brace expansion
- tilde expansion
- parameter and variable expansion
- command substitution
- arithmetic expansion
- word splitting
- filename expansion
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion.
As @socowi points out in his answer, there is a difference between ;
and ,
when it comes to the order of operations, so kinds 2 - 5 are done simultaneously, left to right.
So as you've suspected your book is wrong. Now, I initially suspected that if command substitution would happen after arithmetic expansion we could wind up with situations like:
uberhumus@homepc:~$ kuki=$(echo "if command substitution happens before arithmetic substitution, this $((2+3)) is 5 else it's 2+3")
uberhumus@homepc:~$ echo $kuki
if command substitution happens before arithmetic substitution, this $((2+3)) is 5 else it's $((2+3))
This was wrong. As (echo "if command substitution happens before arithmetic substitution, this $((2+3)) is 5 else it's 2+3")
is a command on its own that means that the expansion order occurs within it too so that situation is impossible.
In fact if you run set -vx
before the above experiment you can see that, as the innermost expansion, $((2+3))
is performed immediately.
uberhumus@homepc:~$ set -vx
uberhumus@homepc:~$ kuki=$(echo "if command substitution happens before arithmetic substitution, this $((2+3)) is 5 else it's 2+3")
kuki=$(echo "if command substitution happens before arithmetic substitution, this $((2+3)) is 5 else it's 2+3")
++ echo 'if command substitution happens before arithmetic substitution, this 5 is 5 else it'\''s 2+3'
+ kuki='if command substitution happens before arithmetic substitution, this 5 is 5 else it'\''s 2+3'
uberhumus@homepc:~$ echo $kuki
echo $kuki
+ echo if command substitution happens before arithmetic substitution, this 5 is 5 else 'it'\''s' 2+3
if command substitution happens before arithmetic substitution, this 5 is 5 else it's 2+3

- 921
- 1
- 13
- 24