我可以在没有“eval”的情况下在 {} 扩展中使用变量吗?

我可以在没有“eval”的情况下在 {} 扩展中使用变量吗?

我可以在{}扩展中使用变量而不吸引吗eval?如果是这样,怎么办?

这不起作用:

$ touch 1.foo 1.bar
$ ls 1.{foo,bar}
1.bar  1.foo
$ extensions=foo,bar
$ ls 1.{$extensions}
ls: cannot access 1.{foo,bar}: No such file or directory

它适用于eval

$ eval ls 1.{$extensions}
1.bar  1.foo

答案1

支撑扩张发生在很早的时候扩张(事实上​​,第一件事)在变量扩展之前。要对变量扩展的结果执行大括号扩展,您需要使用eval.

eval如果您使用extensions通配符模式而不是大括号模式,则可以达到相同的效果。设置extglob激活选项类ksh模式

shopt -s extglob
extensions='@(foo|bar)'
ls 1.$extensions

答案2

这是一种在大括号内扩展变量的方法没有评估:

end=3
declare -a 'range=({'"1..$end"'})'

我们现在有一个很好的数字数组:

for i in ${range[@]};do echo $i;done
1
2
3

在 bash 4.3.11 中测试,但应该适用于所有现代版本。

答案3

您可以在 bash 和其他一些 shell 中使用的另一种技术是使用数组:

$ extensions=(foo bar)
$ ls "${extensions[@]/#/1.}"

这是 参数扩展的(模式替换)形式。 (不幸的是,这也不符合 POSIX 标准。)指定应将替换应用于数组的每个元素,并且应保持元素之间的分隔。  在一个${parameter/pattern/string}[@]#图案字符串的作用类似于^正则表达式中的 a(即大多数替换);这意味着替换只能发生在参数值的开头。所以s/old/new/

$ ls "${extensions[@]/#/1.}"

相当于

$ ls "${扩展名[0]/#/1.}" "${扩展名[1]/#/1.}"

(因为这个数组有两个元素,索引为 0 和 1)并且扩展到

$ ls "1.foo" "1.bar"

引用

如果“扩展名”需要引号,则引号很重要 - 即,如果它们(可能永远)包含空格或路径名扩展(通配符/通配符)字符。例如,如果

$ extensions=("foo bar" "*r")

然后

$ ls ${extensions[@]/#/1.}

(不带引号)将扩展到

$ ls 1.foo bar 1.*r

(其中1.foobar是单独的参数),而这又扩展到

$ ls 1.foo bar 1.anteater 1.bar 1.bear 1.cougar 1.deer 1.grasshopper …

(因为1.*r是一个不带引号的通配符)。有关引用重要性的更多讨论,请参阅忘记在 bash/POSIX shell 中引用变量的安全隐患

您还可以匹配字符串的结尾通过使用%图案:

$ fnames=(cat dog)
$ ls "${fnames[@]/%/.c}"

扩展到

$ ls "cat.c" "dog.c"

但要注意:% $与正则表达式中的工作方式相同。你必须把它放在开始图案 限制匹配发生在参数值的末尾。例如,如果您有

$ fnames=(cat.c dog.c)

你想要得到cat.odog.o, 不做 "${fnames[@]/.c%/.o}"——这是行不通的。做

$ ls "${fnames[@]/%.c/.o}"

但也不要这样做"${fnames[@]/.c/.o}"(完全忽略%)——如果其中一个“fnames”是dog.catcher.c,它将被转换为 (因为dog.oatcher.c第一的 .c被替换为.o)。

不幸的是,没有简单的方法来添加前缀和后缀,就像您可以使用

$ ls 1.{foo,bar}.c

有关变量、数组以及可应用于它们的转换的更多信息,请参阅 bash 文档。

相关内容