シェルが展開する*
非引用された場合にのみ、任意の引用は、シェルによって展開を停止します。
また、ブレース展開は、シェルによって展開されるために引用符で囲まれていない必要があります。
この作業(エコーを使用してシェルの動作を確認します):
$ 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
「パス名拡張」は*.ext1
、およびの2つの引数を受け取ります*.ext2
。
$ set +f
$ echo *.{ext1,ext2}
a.ext1 b.ext1 a.ext2 b.ext2
問題は、ブレース展開に変数を使用できないことです。「ブレース拡張」内で変数
を使用することについては、以前から何度も説明されています。
「変数拡張」の結果である「ブレース拡張」を拡張するには、を使用してコマンドラインをシェルに再送信する必要があります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"
より良い代替案。
代替(evalなし)は、Bashの「拡張パターン」を使用することです。
#!/bin/bash
shopt -s extglob
list='@(ext1|ext2)'
ls -- *.$list
注:両方のソリューション(評価とパターン)(記述どおり)は、スペースまたは改行のあるファイル名に対して安全であることに注意してください。ただし$list
、スペースのあるaの場合は失敗し$list
ます。
eval ls $secondList
はここで正常に動作します...何を達成しようとしていますか?