为什么波形符前缀会在赋值之前展开,而大括号则不会

为什么波形符前缀会在赋值之前展开,而大括号则不会

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

再说一次,为什么波浪号扩展发生在变量赋值之前,但大括号扩展(应该发生在波浪号扩展之前)不会发生在变量赋值之前。想必作业在某种程度上是我不知道的特殊之处。

答案1

在您的测试中,{a..c}不会扩展,因为它是变量赋值的一部分,并进行了处理分别地:

  1. 解析器标记为变量赋值的单词(命令名称前面的单词)和重定向将被保存以供以后处理。
  2. 不是变量赋值或重定向的单词被扩展(参见外壳扩展)。如果扩展后仍有任何单词,则第一个单词将被视为命令名称,其余单词将被视为参数。

分配的值不会进行大括号扩展:

  1. 每个变量赋值中“ ”后面的文本=在赋值给变量之前都会经历波形符扩展、参数扩展、命令替换、算术扩展和引号删除。

答案2

@StephenKitt 的答案指向相关文档(+1),表明该行为是预期的(为什么波浪号前缀在赋值之前扩展,而大括号则不扩展?因为这就是它们的定义方式)。

回复:大括号扩展特殊的一个可能原因,让我们看看是什么发生在变量赋值时:

  • 大括号扩展
  • 单词拆分(解析器拆分行,但不拆分该单词内的扩展结果)
  • 文件名扩展

这些正是可以改变扩展字数的操作:

外壳膨胀:

只有大括号扩展、分词和文件名扩展可以更改扩展的字数

在示例情况中,变量是字符串而不是数组,并且应仅包含一个单词。

支撑扩张分配数组时发生,如brace=({a..c}).使用更复杂的示例:

internal_tilde=({~,~+}/new_dir)
echo "${internal_tilde[@]}"
# /Users/DeNovo/new_dir /Your/Working/Directory/new_dir

因此,我认为这种设计是有意义的(而不是历史上的奇怪现象)。波形符扩展不会改变单词数。大括号扩展确实如此。如果您希望变量包含多个单词,请使用专门为此设计的数据结构。

相关内容