更好的选择。

更好的选择。

我正在尝试扩展一个包含通配符和大括号内指定的扩展名集合的字符串。正如下面的示例所示,似乎没有任何效果。变量firstList扩展得很好,但secondListthirdList或都不能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"

答案1

仅当未加引号时才展开*,任何引用都会阻止 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

为什么这样有效?

重要的是我们要理解为什么它会起作用。这是因为扩展的顺序。首先是“大括号扩展”,然后是(最后一个)“路径名扩展”(又名 glob 扩展)。

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

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

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

“路径名扩展”接收两个参数:*.ext1*.ext2

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

问题是我们不能使用变量进行大括号扩展。
之前已经解释过很多次了在“大括号扩展”中使用变量

要展开作为“变量展开”结果的“大括号展开”,您需要使用 重新将命令行提交到 shell eval

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

支撑 -->多变的--> 全局 || -->支撑--> 变量 -->全局
........ 引用于此 -->^^^^^^ ||评估^^^^^^^^^^^^^^^^^^^^^^^^^^

文件名的值不会给 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"

更好的选择。

另一种选择(无需评估)是使用 Bash“扩展模式”:

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

注意:请注意,两种解决方案(评估和模式)(如所写)对于带有空格或换行符的文件名都是安全的。但对于$list带有空格的a 将失败,因为$list未加引号或 eval 删除了引号。

答案2

考虑:

secondList='*.{ext1,ext2}'
ls $secondList 

问题是大括号扩展已经完成了 变量扩展。这意味着,在上面,从不执行大括号扩展。

这是因为,当 bash 第一次看到命令行时,没有大括号。等扩大之后secondList,就晚了。

以下将起作用:

$ s='*'
$ ls $s.{ext1,ext2}
a.ext1  a.ext2  b.ext1  b.ext2

这里,命令行有大括号,这样大括号扩展可以作为第一步执行。之后,将 的值$s代入 (变量扩展), 最后路径名扩展被执行。

文档

man bash解释扩展的顺序:

展开的顺序是:大括号展开;波形符扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);分词;和路径名扩展。

相关内容