Bash – Nested brace expansion thestery in Bash

bashbrace-expansion

This:

$ echo {{a..c},{1..3}}

produces this:

a b c 1 2 3

Which is nice, but hard to explain given that

$ echo {a..c},{1..3}

gives

a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3

Is this documented somewhere? The Bash Reference doesn't mention it (even though it has an example using it).

Best Answer

Well, it is unravelled one layer at a time:

X{{a..c},{1..3}}Y

is documented as being expanded to X{a..c}Y X{1..3}Y (that's X{A,B}Y expanded to XA XB with A being {a..c} and B being {1..3}), themselves documented as being expanded to XaY XbY XcY X1Y X2Y X3Y.

What may be worth documenting is that they can be nested (that the first } does not close the first { in there for instance).

I suppose shells could have chosen to resolve the inner braces first, like by acting upon each closing } in turn:

  1. X{{a..c},{1..3}}
  2. X{a,{1..3}}Y X{b,{1..3}}Y X{c,{1..3}}Y

    (that is A{a..c}B expanded to AaB AbB AcB, where A is X{ and B is ,{1..3}Y)

  3. X{a,1}Y X{a,2}Y X{a,3}Y X{b,1}Y X{b,2}Y X{b,3}Y X{c,1}Y X{c,2}Y X{c,3}Y

  4. XaY X1Y XaY Xa2...

But I don't find that particularly more intuitive nor useful (see Kevin's example in comments for instance), there would still be some ambiguity as to the order in which the expansions would be done, and that's not how csh (the shell that introduced brace expansion in the late 70s, while the {1..3} form came later (1995) from zsh and {a..c} yet later (2004) from bash) did it.

Note that csh (from the start, see the 2BSD (1979) man page) did document the fact that brace expansions could be nested, though did not explicitly say how nested brace expansions would be expanded. But you can look at the csh code from 1979 to see how it was done then. See how it does explicitly handle nesting indeed, and how it's resolved starting from the outer braces.

In any case, I don't really see how the expansion of {a..c},{1..3} could have any bearing. In there, the , is not an operator of a brace expansion (as it's not inside braces), so is treated like any ordinary character.

Related Question