より良い選択。

より良い選択。

ワイルドカードと中括弧内に指定された拡張子セットを含む文字列を拡張しようとしています。以下の例に示すように、何の効果もないようです。変数は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"

ベストアンサー1

これシェル拡張は引用されていない場合にのみ発生します*。引用すると、シェルは拡張されません。

また、シェルから拡張するには、中かっこ拡張を引用符解除する必要があります。

これはうまくいきます(Echoを使ってシェルが何をしているのか見てみましょう)。

$ 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の2つのパラメータを使用します*.ext2

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

問題は、変数を使用して中括弧拡張を実行できないことです。
これは以前にも何度も説明しました。「分岐拡張」で変数を使用する

「変数拡張」の結果である「中括弧拡張」を拡張するには、コマンドラインをシェルに再送信する必要がありますeval

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

サポート -->変える-->グローバル|-->サポートする-->変数-->全体的な状況
........ここに引用-->^^^^^^ ||評価^^^^^^^^^^^^^^^^^^^^^^^^^^

ファイル名の値は評価実行の問題を引き起こしません。

$ 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

注:2つのソリューション(評価とパターン)(作成したとおり)は、スペースや改行を含むファイル名に対して安全です。ただし、引用符がないか、evalが引用符を削除する$listため、空白がある場合は失敗します。$list

おすすめ記事