tl;dir
In bash, brace expansion occurs before tilde expansion. However, tilde prefixes seem to expand prior to variable assignment and brace expansion doesn't. Why?
Details and examples
Brace expansion in bash is documented as occurring prior to tilde expansion:
Brace expansion is performed before any other expansions
As I understand it, tilde expansion occurs prior to variable assignment, demonstrated by the following example:
# UNQUOTED TILDE PREFIX, TILDE EXPANSION EXPECTED
tilde=~
echo "$tilde"
# /Users/DeNovo
[[ $tilde == "$HOME" ]] && echo "literal match"
# literal match
# QUOTED TILDE PREFIX, TILDE EXPANSION DOES NOT OCCUR
lit_tilde='~'
echo "$lit_tilde"
# ~
# UNQUOTED TILDE PREFIX PRODUCED AND EVALUATED, TILDE EXPANSION OCCURS
# AS EXPECTED
eval echo "$lit_tilde"
# /Users/DeNovo
[[ $lit_tilde == "~" ]] && echo "literal match"
# literal match
These examples would seem to suggest that the right operand of left=right
undergoes tilde expansion before being bound as the value to the left operand.
Brace expansion, however, does NOT occur before variable assignment, with similar behavior to binding a literal tilde to a variable (vs. a special character/prefix that is expanded)
# UNQUOTED BRACE, BUT NO EXPANSION. BRACE LITERAL IS PRESERVED
brace={a..c}
echo "$brace"
# {a..c}
[[ $brace = "a b c" ]] || echo "doesn't match"
# doesn't match
[[ $brace = "{a..c}" ]] && echo "literal match"
# literal match
# SIMILAR TO THE LITERAL TILDE, EVALUATING THE VARIABLE VALUE
# RESULTS IN BRACE EXPANSION
eval echo "$brace"
# a b c
Combining the two expansions into one example, you can see tilde expansion occurs and brace expansion does not:
combined=~/dir_{a..c}
echo "$combined"
# /Users/DeNovo/dir_{a..c}
And braces prevent internal tilde's from expanding during assignment
internal_tilde={~,~+}/new_dir
echo "$internal_tilde"
# {~,~+}/new_dir
# vs the same output, not in a variable
echo {~,~+}/new_dir
/Users/DeNovo/new_dir /Your/Working/Directory/new_dir
Just to clarify, I'm not asking how to get a variable to contain the result of brace expansion, but why, despite occurring before tilde expansion, brace expansion doesn't occur before variable assignment. There are several ways to get the desired behavior. Here is one:
# PROCESS SUBSTITUTION GIVES THE DESIRED BEHAVIOR
brace_exp="$(echo {a..c})"
echo "$brace_exp"
a b c
[[ $brace_exp = "a b c" ]] && echo "literal match"
# literal match
So again, why does tilde expansion occur before variable assignment, but brace expansion (which is supposed to occur before tilde expansion) doesn't occur before variable assignment. Presumably assignment is special in some way that I'm not aware of.