更好的選擇。

更好的選擇。

我正在嘗試擴展一個涉及通配符和大括號內指定的擴展名集合的字串。正如下面的範例所示,似乎沒有任何效果。變數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解釋擴展的順序:

展開的順序是:大括號展開;波形符擴展、參數和變數擴展、算術擴展和命令替換(以從左到右的方式完成);分詞;和路徑名擴展。

相關內容