{a,b,c}什么时候用bash扩展,什么时候不扩展?


13

一个bash脚本,其中包含

for i in {a,b}-{1,2}; do
  echo $i;
done

版画

a-1
a-2
b-1
b-2

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

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

v={a,b}-{1,2}
echo $v

它打印

{a,b}-{1,2}

这不是我所期望的。我希望它能打印出来a-1 a-2 b-1 b-2。显然,该{a,b}构造未扩展。

我可以像这样使它扩展

v=$(echo {a,b}-{1,2})

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


1
这至少与您不能使用simple制作数组变量的事实一致=。例如,v=a-1 a-2将不起作用。
grochmal

@grochmal-这是因为您要分配标量值。 v=a-1 a-2表示assign 'a-1' to variable v and run 'a-2' v=(a-1 a-2)将数组分配给variable vv+=(b-1 b-2)追加到它。
cas

Answers:


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.

括号扩展不在列表中,因此未对赋值执行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.

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

但是您可以执行以下操作:

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar

以扩大它$(echo ...),如果你没有在字符串中的任何空白加以扩展,因此将无法运行与分词的问题应该工作。如果可以的话,更好的方法可能是使用数组变量。

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

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"

5

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

变量可以通过以下形式的语句被分配给

      名称 = [ ]

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

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

但是,这仍然存在一个问题,即:shell如何知道这是一个变量分配,因此不需大括号扩展?或更准确地说,解析序列在哪里得到澄清和编码,以便在定义外壳程序以处理大括号扩展之前定义其变量分配?(这显然是如何bash工作的,但是我还没有找到描述此内容的确切文件。)


1
也许这样吗?“ 2.不是变量分配或重定向的单词将被扩展(请参阅Shell Expansions)。”
Jeff Schaller

@JeffSchaller,你是对的。实际上,只需阅读“简单命令扩展”(LESS=+/SIMPLE man bash)部分,便可以最好地回答该问题。
2016年

0

据我所知,{a,b,c}在直接回显或与命令一起使用时会被扩展,例如:mkdir〜/ {a,b,c},但是当将其设置为变量时,应先评估回显它或将其用作参数!

u@h:~$ echo {a,b}-{1,2}
a-1 a-2 b-1 b-2
u@h:~$ v={a,b}-{1,2}
u@h:~$ echo $v
{a,b}-{1,2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

由于您的字母顺序为[a],字母顺序为[az],后接“ b”,而字母的顺序为[0-9],字母顺序为“ 1”,后接“ 2”:您可以使用双句号“ ..”代替逗号“, ”

u@h:~$ echo {a..b}-{1..2}
a-1 a-2 b-1 b-2
u@h:~$ v={a..b}-{1..2}
u@h:~$ echo $v
{a..b}-{1..2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

1
问题是为什么v没有将其设置为文字字符串“ a-1 a-2 b-1 b-2”。或至少为什么键入以下命令时不会出现任何错误:(v=a-1 v=a-2 v=b-1 v=b-2您希望将变量赋值扩展为)。这是一个好问题;这并不能真正回答。
通配符

@SatoKatsura,“通配符扩展”应该是什么意思?有参数扩展,路径名扩展和花括号扩展-您可能要引用的所有参数都不同。还是您是说分词?
通配符

0

在bash中分配变量不会扩展表达式。

对于这个小脚本,x将包含"*"而不是扩展"*"

#!/bin/bash
x=*
echo "$x"

但是,有些值被扩展,参考。ilkkachu的一个不错的答案。

对表达式求值时将对其进行扩展。

像这样:

x=$(echo *)        # <-- evaluation of "*"
echo "$x"

或像这样:

x=*
echo $x            # <-- evaluation of $x

或像这样:

x=*
eval echo "$x"     # <-- evaluation of `echo *`

触发$()是相当普遍的,我认为它是首选eval,但最好的办法是根本不触发评估,直到在命令中实际使用了变量为止。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.