简体   繁体   中英

Order of brace expansion and parameter expansion

A common trope on StackOverflow is: "Why doesn't x=99; echo {1..$x} work?" The answer is "because braces are expanded before parameters/variables" .

Therefore, I thought it should be possible to expand multiple variables using a single $ and a brace. I'd expect a=1; b=2; c=3; echo ${{a..c}} a=1; b=2; c=3; echo ${{a..c}} a=1; b=2; c=3; echo ${{a..c}} to print 1 2 3 . First, the inner brace would expand to ${a} ${b} ${c} (which it does when writing echo \\${{a..c}} ). Then that result would undergo parameter expansion.
However, I got -bash: ${{a..c}}: bad substitution so {a..c} wasn't expanded at all.

Bash's manual is a bit more specific (emphasis mine).

Expansion is performed on the command line after it has been split into tokens [...] 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.

Note the ; and , in that list. "Left-to-right fashion" seems to apply to the whole (therefore unordered) list before the ; . Just like the mathematical operators * and / have no precedence over each other.

Ok, so brace expansion is not really of higher precedence than parameter expansion. It's just that both {1..$x} and ${{a..c}} are evaluated from left to right, meaning the brace { comes before the parameter $x and the parameter ${ comes before the brace {a..c} .

Or so I thought. However, when using $ instead of ${ then parameters on the left expand after braces on the right:

# in bash 5.0.3(1)
x=nil; x1=one; x2=two
echo ${x{1..2}} # prints `-bash: ${x{1..2}}: bad substitution`
echo $x{1..2}   # prints `one two`

Question

  • Could it be that the bash manual is flawed or did I read it wrong?
  • If the manual is flawed: What is the exact order of all expansions?

I'm just asking because I'm curious. I don't plan to use thinks like $x{1..2} anywhere. I'm not interested in better solutions or alternatives to address multiple variables (eg array slices ${array[@]:1:2} ). I just want to get a deeper understanding.

from: https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html

To avoid conflicts with parameter expansion, the string '${' is not considered eligible for brace expansion, and inhibits brace expansion until the closing '}'.

That said, for echo $x{1..2} , first the brace expansion takes place, and then the parameter expansion, so we have echo $x1 $x2 . For echo ${x{1..2}} the brace expansion doesn't happen, because we are after the ${ and haven't reached the closing } of the parameter expansion.

Regarding the bash manual part you have quoted, left-to-right order still exists for the expansions (with respect to allowed nested ones). Things get clearer if you format the list instead of using , and ; :

  1. brace expansion
  2. In a left-to-right fashion:
    tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution
  3. word splitting
  4. filename expansion.

Read Mo Budlong's 1988 classic Command Line Psychology , which was written for regular Unix, but most of it still applies to bash . The order of evaluation goes:

1 History substitution (except for the Bourne shell)
2 Splitting words, including special characters
3 Updating the history list (except for the Bourne shell)
4 Interpreting single and double quotes
5 Alias substitution (except for the Bourne shell)
6 Redirection of input and output (< > and |)
7 Variable substitution (variables starting with $)
8 Command substitution (commands inside back quotes)
9 File name expansion (file name wild cards) 

So what bash does with code like {1..3} happens before step 7 above, and that's why the OP code fails.

But if we must, there's always eval , (which should only be used if the variables are known in advance, or first cautiously type checked):

a=1; b=2; c=3; eval echo \{$a..$c}

Output:

1 2 3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM