Order of shell expansions: command substitution versus arithmetic expansion

Consider the following snippet being entered at the command line in bash:

$ echo $(( $(wc -l letter.txt | cut -c1-4)/66 + 1))

Supposing letter.txt exists and has 66*4 lines, then this puts the string 5 on the command line. Now what I cannot follow is how this conclusion follows based on what I know about command line processing.

My book (Sobell’s A Practical Guide to Linux, 4e) says

The Bourne Again Shell scans each token for the various types of expansion and sub- stitution in the following order. Most of these processes expand a word into a single word. Only brace expansion, word splitting, and pathname expansion can change the number of words in a command (except for the expansion of the variable "$@"— see page 474).

  1. Brace expansion (next page)
  2. Tilde expansion (page 368)
  3. Parameter and variable expansion (page 368)
  4. Arithmetic expansion (page 369)
  5. Command substitution (page 371)
  6. Word splitting (page 372)
  7. Pathname expansion (page 372)
  8. Process substitution (page 374)
  9. Quote removal (page 374)

Based on the above, it would seem that the arithmetic expansion would evaluate first and, if so, the token $(wc -l letter.txt | cut -c1-4) is not a valid operand for the integer arithmetic which bash deals with. What is my way out here/what am I not understanding?

Asked By: EE18


Your book is not exactly correct. See man bash for the exact 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.

Note the usage of commas and semicolons. The parameter, variable, and arithmetic expansions plus the command substitution all happen with the same order.

The manual says the following about arithmetic expansion:

All tokens in the expression undergo parameter and variable expansion, command substitution, and quote removal.

And command substitution is described as

… executing command in a subshell environment

which means all expansions take place when nested from inside out.

$ echo $((1 + $(echo $((2+$(printf %s 3))))))
Answered By: choroba
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.