shopt:“&&”有什么问题?

shopt:“&&”有什么问题?

我不明白为什么当我单独执行它们时它可以工作,但同时执行&&它们却不行(这不是(像这里这样的问题)...我错过了什么?

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

由于第一个版本都在一行上,因此 shell 必须在执行任何内容之前解析整个内容。但**/*.@(jpg|jpeg|png|gif)只有有效的语法shopt -s extglob执行后...这是在该行经过解析阶段之后。

如果这必须是一行代码,我不知道有什么好办法可以解决这个问题。但是你应该能够使用括号扩展而不是扩展的 glob 来作弊,并修改 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;

...然后每个通配符模式都会被单独扩展。这样做有一个潜在的问题:如果没有至少一个文件与这四个模式中的每一个相匹配,那么不匹配的模式将被保留下来,作为虚假的占位符。

例如,如果只有 .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,这会使不匹配的通配符消失。

相关内容