12

I have 3 files in a directory:

aaa.jpg    
bbb.jpg  
ccc.jpg  

I can scale down an image using ImagkMagick convert:

convert aaa.jpg -resize 1200x900 aaa-small.jpg  

I want to do all the images in the directory, something like:

convert *.jpg -resize 1200x900 *-small.jpg  

but this results in files named like so:

*-small-0.jpg  
*-small-1.jpg  
*-small-2.jpg  

What I want is:

aaa-small.jpg  
bbb-small.jpg  
ccc-small.jpg  

How do I do this?

muru
  • 193,181
  • 53
  • 473
  • 722
Al Lelopath
  • 589
  • 1
  • 5
  • 22
  • Mogrify is the ImageMagick command designed for batch jobs. Question is a related to and possibly a duplicate of this one: https://superuser.com/questions/597428/how-can-i-run-mogrify-but-prefix-the-filename – Brian Z Jul 28 '21 at 11:07

3 Answers3

17

It's frustratingly opaque in the documentation, but you can pass a quoted shell glob to convert (quoted to prevent the shell from expanding it prematurely), and use Filename Percent Escapes to construct output filenames in the form %[filename:label] (where label is an arbitrary user-specified label), using the input basename escape %[basename] or its legacy equivalent %t:

$ ls ???.jpg
aaa.jpg  bbb.jpg  ccc.jpg

then

$ convert '*.jpg' -set filename:fn '%[basename]-small' -resize 1200x900 '%[filename:fn].jpg'

resulting in

$ ls ???-small.jpg
aaa-small.jpg  bbb-small.jpg  ccc-small.jpg
steeldriver
  • 131,985
  • 21
  • 239
  • 326
  • 1
    This approach loads all files into memory at the same time, so if you try to process tens or hundreds of files (not just 3), you might hit ImageMagick's "cache resources exhausted" error. You could edit `/etc/ImageMagick-6/policy.xml` to allow for more memory, but a shell loop might be easier. – Sampo Smolander Sep 11 '22 at 20:31
10

In a for loop it is possible to use the features described in man bash at

Parameter Expansion
...
  ${parameter%word}
  ${parameter%%word}
      Remove matching suffix pattern.  The word is expanded to produce a pattern just
      as in pathname expansion.  If the pattern matches  a  trailing portion  of the
      expanded  value of parameter, then the result of the expansion is the expanded
      value of parameter with the shortest matching pattern (the ``%'' case) or the
      longest matching pattern (the ``%%'' case) deleted.  If parameter is @ or *,
      the pattern removal operation is applied  to  each positional parameter in turn,
      and the expansion is the resultant list.  If parameter is an array variable
      subscripted with @ or *, the pattern removal operation is applied to each member
      of the array in turn, and the expansion is the resultant list.

The following one-liner should do the job

for f in ./*.jpg ; do convert "$f" -resize 1200x900 "${f%.jpg}-small.jpg" ; done

This works in bash, which is the standard shell of Ubuntu. I think it is easier to remember than the elegant method by Steeldriver (who uses only convert and no for construct).

Nathan Musoke
  • 195
  • 1
  • 4
sudodus
  • 45,126
  • 5
  • 87
  • 151
-2
mkdir small
for f in *.jpg ; do convert $f -resize 1200x900 small/$f ; done
Wayne Vosberg
  • 748
  • 3
  • 5