bash将通配符扩展与大括号扩展相结合

我正在尝试扩展一个涉及通配符和大括号中指定的扩展集合的字符串.似乎没有什么工作,如下面的例子所示.变量firstList扩展正常,但secondList,thirdList或fourthList都没有正确扩展.我也尝试了各种版本的eval,但也没有.任何帮助,将不胜感激

#!/bin/bash
touch a.ext1
touch b.ext1
firstList='*.ext1'
ls  $firstList
touch a.ext2
touch b.ext2
secondList='*.{ext1,ext2}'
ls $secondList 
ls '$secondList'
ls "$secondList"
thirdList=*.{ext1,ext2}
ls $thirdList  
ls '$thirdList'
ls "$thirdList"
fourthList="*.{ext1,ext2}"
ls $fourthList
ls '$fourthList'
ls "$fourthList"
最佳答案
shell仅在未引用时展开*,任何引用都会停止shell的扩展.

此外,支撑扩展需要不加引号以由shell扩展.

这项工作(让我们使用echo来查看shell的作用):

$echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

即使有一些其他名称的文件:

$touch {a,b}.{ext1,ext2} {c,d}.{ext3,ext4} none
ls
a.ext1  a.ext2  b.ext1  b.ext2  c.ext3  c.ext4  d.ext3  d.ext4  none

$echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

为什么这样有效?

重要的是我们理解为什么这样有效.这是因为扩张的顺序.首先是“Brace扩展”,后来(最后一个)“Pathname Expansion”(a.k.a glob-expansion).

Brace --> Parameter (variable) --> Pathname

我们可以暂时关闭“路径名扩展”:

$set -f
$echo *.{ext1,ext2}
*.ext1 *.ext2

“Pathname Expansion”接收两个参数:* .ext1和* .ext2.

$set +f
$echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2

问题是我们不能使用变量进行大括号扩展.
之前已经多次解释过using a variable inside a “Brace Expansion”

要扩展“可变扩展”结果的“Brace扩展”,您需要使用eval将命令行重新提交到shell.

$list={ext1,ext2}
$eval echo '*.'"$list"

Brace –> Variable –> Glob || –> Brace –> Variable –> Glob
…….. quoted here –>^^^^^^ || eval ^^^^^^^^^^^^^^^^^^^^^^^^^

文件名的值不会为eval带来执行问题:

$touch 'a;date;.ext1'
eval echo '*.'"$list"
a;date;.ext1 a.ext1 b.ext1 a.ext2 b.ext2

但$list的价值可能不安全.但是,$list的值由脚本编写者设置.脚本编写者控制eval:只是不使用$list的外部设置值.试试这个:

#!/bin/bash
touch {a,b,c}.ext{1,2}
list=ext{1,2}
eval ls -l -- '*.'"$list"

一个更好的选择.

另一种选择(没有评估)是use Bash “Extended Patterns”

#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list

注意:请注意,对于带有空格或换行符的文件名,两种解决方案(eval和patterns)(如已编写)都是安全的.但是对于带有空格的$list会失败,因为$list是不引用的,或者eval删除了引号.

转载注明原文:bash将通配符扩展与大括号扩展相结合 - 代码日志