ワイルドカードと中かっこ内で指定された拡張子のコレクションを含む文字列を展開しようとしています。以下の例が示すように、何も機能しないようです。変数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は、引用符で囲まれていない場合にのみ*
を展開します。引用符を付けると、シェルによる展開が停止します。
また、ブレース展開は、シェルによって展開されるために引用符で囲まれていない必要があります。
この作業(エコーを使用してシェルの動作を確認します):
$ 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-expansion)。
Brace --> Parameter (variable) --> Pathname
「パス名拡張」を少しの間オフにすることができます:
$ set -f
$ echo *.{ext1,ext2}
*.ext1 *.ext2
「パス名拡張」は、2つの引数*.ext1
および*.ext2
を受け取ります。
$ set +f
$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2
問題は、ブレース展開に変数を使用できないことです。
以前に何度も説明されてきましたが、 「ブレース拡張」内で変数を使用する
「変数拡張」の結果である「ブレース拡張」を拡張するには、eval
を使用してコマンドラインをシェルに再送信する必要があります。
$ list={ext1,ext2}
$ eval echo '*.'"$list"
ブレース->変数->グロブ|| ->Brace->変数->Glob
........ここで引用-> ^^^^^^ ||評価^^^^^^^^^^^^^^^^^^^^^^^^^
ファイル名の値は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"
代替(evalなし)は、 Bashの「拡張パターン」 を使用することです。
#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list
注:両方のソリューション(評価とパターン)(記述どおり)は、スペースまたは改行のあるファイル名に対して安全であることに注意してください。ただし、$list
は引用符で囲まれていないか、evalが引用符を削除するため、スペースを含む$list
の場合は失敗します。
考慮してください:
secondList='*.{ext1,ext2}'
ls $secondList
問題は、ブレース展開が行われることですbefore変数展開。つまり、上記ではブレースの展開は行われません。
これは、bashが最初にコマンドラインを表示するとき、中かっこがないためです。 secondList
を展開した後では、手遅れです。
以下が機能します:
$ s='*'
$ ls $s.{ext1,ext2}
a.ext1 a.ext2 b.ext1 b.ext2
ここでは、コマンドラインに中かっこが付いているため、中かっこ展開を最初のステップとして実行できます。その後、$s
の値が(変数展開)に代入され、最後にパス名展開が実行されます。
man bash
は、展開の順序を説明しています。
展開の順序は次のとおりです。チルダ展開、パラメーターと変数の展開、算術展開、およびコマンド置換(左から右に実行)。単語分割;およびパス名の展開。