なぜそれらを個別に実行すると機能するのかわかりませんが、&&
では機能しません(これは (
のような問題ではありません )...何が欠けていますか?
11:20:06 $ shopt -s extglob && shopt -s globstar && for f in **/*.@(jpg|jpeg|png|gif); do [[ -f "$f.webp" ]] || cwebp -quiet -q 80 "$f" -o "$f.webp"; done
bash: syntax error near unexpected token `('
11:20:11 $ shopt -s extglob && shopt -s globstar
11:20:16 $ for f in **/*.@(jpg|jpeg|png|gif); do [[ -f "$f.webp" ]] || cwebp -quiet -q 80 "$f" -o "$f.webp"; doneError! Could not process file img/colorpicker/colormap.gif
11:20:23 $
最初のバージョンはすべて1行になっているので、シェルは実行する前にすべてを解析する必要があります。ただし、**/*.@(jpg|jpeg|png|gif)
は有効な構文ですshopt -s extglob
が実行された後 ...これは、行が解析フェーズを通過した後です。
これがワンライナーである必要がある場合、私はそれを回避する素晴らしい方法を知りません。しかし、拡張グロブの代わりにブレース展開を使用して、test-for-filesを変更することで、チートできるはずです。
shopt -s globstar && for f in **/*.{jpg,jpeg,png,gif}; do [[ -f "$f" && ! -f "$f.webp" ]] && cwebp -quiet -q 80 "$f" -o "$f.webp"; done
globstar
はワイルドカードが展開されたときに有効になるため、最初の解析パスでは有効にならないため、この問題は適用されないことに注意してください。
説明:bashはワイルドカードを展開する前に展開をブレースします。
for f in **/*.{jpg,jpeg,png,gif};
に拡大する
for f in **/*.jpg **/*.jpeg **/*.png **/*.gif;
...そして、それらのワイルドカードパターンのそれぞれが個別に展開されます。これには潜在的な問題があります。4つのパターンのそれぞれに一致するファイルが1つもない場合、一致しないパターンは、一種の偽のプレースホルダーとして残されます。
たとえば、.jpgファイルと.pngファイルしかない場合、完全に展開されたリストには次のようなものが含まれます。
path/to/image1.jpg
path/to/image2.jpg
**/*.jpeg
path/to/image3.png
**/*.gif
...そして先に進み、**/*.jpeg
と**/*.gif
を含むそれぞれのループを実行します。そのため、ループ内のテストを変更して、
[[ -f "$f" && ! -f "$f.webp" ]] && cwebp ...
-f "$f"
テストは、展開されていないワイルドカードでは失敗し、存在しないファイルのwebpバージョンを作成しようとするのを防ぎます。これを同等に使用できます。これは、元のテストに近いものです。
[[ ! -f "$f" || -f "$f.webp" ]] || cwebp ...
でも他の方が直感的だったけどね。
ところで、一致しないワイルドカードの問題に対する別の可能な修正は、shopt -s nullglob
を追加することです。これにより、一致しないものは消えます。