18

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
  • 207,228

4 Answers4

23

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
  • 142,475
14

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

sudodus
  • 47,684
1

This is the type of thing that scripting languages were created for. I wanted to convert a bunch of .webp files to .jpg using convert and wrote this script in Perl.

#!/usr/bin/perl -w

while(<>){
  chomp;
  my ($o, $n) = ($_,s/\.webp$/\.jpg/ri);
  $cmd= "convert \"$o\" \"$n\"";
  print "$cmd\n";
  `$cmd`;
}

I can change this around a little bit and make it work to resize files like so...

#!/usr/bin/perl -w

while(<>){ chomp; my ($o, $n) = ($_,s/.jpg$/-small.jpg/ri); $cmd= "convert &quot;$o&quot; -resize 1200x900 &quot;$n&quot;"; print "$cmd\n"; $cmd; }

Run it like this...

$ ls *.jpg | perl resizePictures.pl

Output looks like this...

convert "1639ce10-b1fe-11ed-bdfd-366dddef2df0.jpg" -resize 1200x900 "1639ce10-b1fe-11ed-bdfd-366dddef2df0-small.jpg"
convert "gulf.stream.jpg" -resize 1200x900 "gulf.stream-small.jpg"
convert "main-qimg-2c580245b682a77cb5cf0348f3bbf73c.jpg" -resize 1200x900 "main-qimg-2c580245b682a77cb5cf0348f3bbf73c-small.jpg"
convert "work.jpg" -resize 1200x900 "work-small.jpg"

Golfed at 69 characters

 ls *.jpg | perl -ne 'chomp;$n=s/\.jpg$/-small\.jpg/ri;`convert "$_" -resize 1200x900 "$n"`;'
0
mkdir small
for f in *.jpg ; do convert $f -resize 1200x900 small/$f ; done