Search code examples
bashimage-processingimagemagickzsh

ImageMagick vs. Bash/Zsh: Using *.(format1|format2) vs. "*.{format1,format2}"


To check whether filename extensions of my images are correct, that is, whether my JPEGs are really JPEGs, PNGs are really PNGs, and WebPs are really WebPs, I can use the following ImageMagick command:

magick identify -format "%f: %m\n" *.(jp*|png|webp)

Or I can use "*.{jp*,png,webp}" instead:

magick identify -format "%f: %m\n" "*.{jp*,png,webp}"

Note the quotation marks. Otherwise, if your target folder won't contain at least one file of each format, there will be an error.

magick identify -format "%f: %m\n" *.{jp*,png,webp}
zsh: no matches found: *.webp

ImageMagick itself supports both *.(foo|bar|barz) and "*.{foo,bar,baz}" syntaxes, but Zsh on my macOS, and I suppose Bash on Linux and BSD, supports only the first one, with parentheses ().

# works
file *.(jp*|png|webp)
# doesn't work at all. the {} syntax is not
# supported by Zsh and probably Bash
file *.{jp*,png,webp}

Hence my question. Which syntax should we prefer in ImageMagick scripts (for example, when using magick identify): with (), which is supported by both ImageMagick and Zsh/Bash, or with {}, which is supported by ImageMagick only?


A summary of my and Fred's (fmw42) tests

Bash Zsh
magick identify *.(jpg|png)
magick identify *.{jpg,png} ✓†
magick identify "*.{jpg,png}"
Bash Zsh
file *.(jpg|png)
file *.{jpg,png} ✓‡ ✓†
file "*.{jpg,png}"

✓ - Works. You can have a) both JPGs and PNGs or b) PNGs only or c) JPGs only or d) none
✓† - Works, but you must have at least one JPG and one PNG
✓‡ - Works, but if you don't have at least one JPG and one PNG, there will be a warning
– - Doesn't work

GNU bash, version 3.2.57(1)-release (arm64-apple-darwin23)
zsh 5.9 (x86_64-apple-darwin23.0)


Solution

  • On my M1 Mac OSX Ventura in bash, I get

    magick identify -format "%f: %m\n" *.(jp*|png|webp)
    
    bash: syntax error near unexpected token `('
    

    but

    magick identify -format "%f: %m\n" "*.{jp*,png,webp}"
    
    barn.jpg: JPEG
    image.png: PNG
    lena.jpg: JPEG
    lena.png: PNG
    mandril3.jpg: JPEG
    monet2.jpg: JPEG
    redhat.jpg: JPEG
    zelda1.jpg: JPEG
    

    So it seems to me that the latter is better in bash.

    In zsh, I get

    magick identify -format "%f: %m\n" *.(jp*|png|webp)
    barn.jpg: JPEG
    image.png: PNG
    lena.jpg: JPEG
    lena.png: PNG
    mandril3.jpg: JPEG
    monet2.jpg: JPEG
    redhat.jpg: JPEG
    zelda1.jpg: JPEG
    

    and

    magick identify -format "%f: %m\n" "*.{jp*,png,webp}"
    barn.jpg: JPEG
    image.png: PNG
    lena.jpg: JPEG
    lena.png: PNG
    mandril3.jpg: JPEG
    monet2.jpg: JPEG
    redhat.jpg: JPEG
    zelda1.jpg: JPEG
    

    So zsh does a better job than bash with the () notation and the same as in bash with the {} notation

    In bash for find, I get

    file *.(jp*|png|webp)
    bash: syntax error near unexpected token `('
    

    and

    file "*.{jp*,png,webp}"
    *.{jp*,png,webp}: cannot open `*.{jp*,png,webp}' (No such file or directory)
    

    and

    For zsh for find, I get

    file *.(jp*|png|webp)
    
    barn.jpg:     JPEG image data, JFIF standard 1.01, resolution (DPCM), density 28x28, segment length 16, comment: "bdh 11110000110100001100100011001010110110011100100101001101011011101010101010101011100111011001101001110000011111000101110010", baseline, precision 8, 400x299, components 3
    image.png:    PNG image data, 314 x 88, 8-bit/color RGBA, non-interlaced
    lena.jpg:     JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 256x256, components 3
    lena.png:     PNG image data, 256 x 256, 8-bit/color RGB, non-interlaced
    mandril3.jpg: JPEG image data, JFIF standard 1.01, resolution (DPCM), density 28x28, segment length 16, baseline, precision 8, 256x256, components 3
    monet2.jpg:   JPEG image data, baseline, precision 8, 265x333, components 3
    redhat.jpg:   JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, baseline, precision 8, 254x255, components 3
    zelda1.jpg:   JPEG image data, JFIF standard 1.01, resolution (DPCM), density 28x28, segment length 16, baseline, precision 8, 256x256, components 3
    

    and

    file "*.{jp*,png,webp}"
    
    *.{jp*,png,webp}: cannot open `*.{jp*,png,webp}' (No such file or directory)