13

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?

1

3 Answers 3

18

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
1
  • 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. Sep 11, 2022 at 20:31
11

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).

3
  • 2
    +1 because it follows the Unix philosophy that each tool should do small part of the work efficiently, rather than one tool does everything. Jul 27, 2021 at 11:51
  • 3
    I suggest changing the filenames from *.jpg to ./*.jpg in case some name begins with -.
    – 7efkvNEq
    Jul 27, 2021 at 15:13
  • @7efkvNEq, Thanks, that's a good idea.
    – sudodus
    Jul 27, 2021 at 15:21
-1
mkdir small
for f in *.jpg ; do convert $f -resize 1200x900 small/$f ; done
2
  • 1
    This does not answer the question. The filenames are the same. Jul 26, 2021 at 19:10
  • @AlLelopath, True, the filenames are the same, but in another directory. I have used this method and I think it is good ;-)
    – sudodus
    Jul 26, 2021 at 20:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .