{a,b,c} 什么时候在 bash 中展开,什么时候不展开?

Ren*_*ger 13 bash brace-expansion

一个 bash 脚本,包含

for i in {a,b}-{1,2}; do
  echo $i;
done
Run Code Online (Sandbox Code Playgroud)

印刷

a-1
a-2
b-1
b-2
Run Code Online (Sandbox Code Playgroud)

执行时。这是我所期望的 - 随着{a,b}构造的扩展。

但是,当(另一个)脚本包含

v={a,b}-{1,2}
echo $v
Run Code Online (Sandbox Code Playgroud)

它打印

{a,b}-{1,2}
Run Code Online (Sandbox Code Playgroud)

这不是我所期望的。我预计它会打印a-1 a-2 b-1 b-2。显然,该{a,b}构造没有展开。

我可以让它像这样扩展

v=$(echo {a,b}-{1,2})
Run Code Online (Sandbox Code Playgroud)

基于这些观察,我有两个问题:1)何时{a,b}扩展构造?2) 是$(echo {a,b}-{1,2})在需要时触发扩展的首选方式吗?

ilk*_*chu 15

猛砸手册说:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the following
expansions, assignments, and redirections, from left to right.
[...]
4. The  text  after the = in each variable assignment undergoes tilde
   expansion, parameter expansion, command substitution, arithmetic
   expansion, and quote removal before being assigned to the variable.
Run Code Online (Sandbox Code Playgroud)

大括号扩展不在列表中,因此不会为 assignment 执行v={a,b}-{1,2}。正如@Wildcard 所提到的,v=a-1 v=b-1 ...无论如何简单的扩展都是毫无意义的。

此外,在执行 时echo $v,以下适用:

EXPANSION
Expansion is performed on the command line after it has been split
into words. [...]

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
pathname expansion.
Run Code Online (Sandbox Code Playgroud)

大括号扩展发生在变量扩展之前,因此分配给的大括号$v不会被扩展。

但是你可以做这样的事情:

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar
Run Code Online (Sandbox Code Playgroud)

$(echo ...)如果要扩展的字符串中没有任何空格,则扩展它应该可以工作,因此不会遇到分词问题。如果可以,更好的方法可能是使用数组变量。

例如,将扩展保存到数组中并使用扩展值运行一些命令:

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"
Run Code Online (Sandbox Code Playgroud)


Wil*_*ard 5

一个有趣的点。以下摘录可能有帮助man bash

一个变量可以通过以下形式的语句赋值

      名称=[]

如果未给出值,则为变量分配空字符串。所有值都经过波浪号扩展、参数和变量扩展、命令替换、算术扩展和引号删除(参见下面的扩展)。

请注意,列表中未提及大括号扩展。

然而,这仍然留下一个问题,即:shell 如何知道这是一个变量赋值,因此不受大括号扩展的影响?或者更准确地说,解析序列在哪里澄清和编码,以便定义 shell 以在处理大括号扩展之前识别变量赋值?(这显然是如何bash工作的,但我还没有找到描述这一点的确切文档行。)