我可以在{}
扩展中使用变量而不吸引吗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
答案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.foo
和bar
是单独的参数),而这又扩展到
$ 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.o
和dog.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 文档。