tl;目录
在 bash 中,大括号扩展发生在波浪号扩展之前。但是,波浪号前缀似乎在变量赋值之前扩展,而大括号扩展则没有。为什么?
细节和例子
bash 中的大括号扩展被记录为发生在波浪线扩展之前:
大括号扩展在任何其他扩展之前执行
据我了解,波浪号扩展发生在变量赋值之前,如下例所示:
# 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
这些例子似乎表明右操作数left=right
在被绑定为左操作数的值之前经历波浪号扩展。
然而,大括号扩展不会发生在变量赋值之前,其行为类似于将文字波浪号绑定到变量(相对于扩展的特殊字符/前缀)
# 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
将这两个扩展合并到一个示例中,您可以看到波浪号扩展发生而大括号扩展没有发生:
combined=~/dir_{a..c}
echo "$combined"
# /Users/DeNovo/dir_{a..c}
大括号防止内部代字号在分配期间扩展
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
只是为了澄清,我不是在问如何让变量包含大括号扩展的结果,而是为什么尽管发生在波浪线扩展之前,大括号扩展不会在变量赋值之前发生。有几种方法可以获得所需的行为。这是一个:
# 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
再说一遍,为什么波浪号扩展发生在变量赋值之前,而大括号扩展(应该发生在波浪号扩展之前)却没有发生在变量赋值之前。大概分配在某种我不知道的方面是特殊的。
在您的测试中,
{a..c}
未展开,因为它是变量赋值的一部分,并单独处理:分配的值不进行大括号扩展:
@StephenKitt 的回答指向相关文档 (+1),表明该行为是预期的(为什么波浪号前缀在赋值之前扩展但大括号不扩展?因为它们就是这样定义的)。
回复:大括号扩展很特殊的一个可能原因,让我们看看变量赋值时没有发生什么:
这些正是可以改变扩展字数的操作:
外壳扩展:
在示例中,变量是一个字符串而不是一个数组,并且应该只包含一个单词。
分配数组时确实会发生大括号扩展,如
brace=({a..c})
. 要使用更复杂的示例:所以,我认为这种设计是有道理的(而不是历史上的怪事)。波浪号扩展不会改变字数。大括号扩展确实如此。如果您希望您的变量包含多个单词,请使用专为此设计的数据结构。