Replacing file extensions in a Bash for loop

I've had to look this up on the internet several times, so I've finally decided to write an article about it so I'll know where to look next time.

Sometimes I want to do an operation on a large number of files (like scaling a bunch of pictures before uploading to Facebook, for example.) There is a way to use a Bash "for" loop, to have a program iterate over the list of files. However, since I don't want to replace the file, I need to specify a different output filename for the program, something related to the original filename (like filename_small.jpg)

To do this in Bash, you use the % variable modifier. For example, if you have a directory of images (filename.jpg) and you want to create thumbnails of these images (filename_small.jpg), you could do this:

for i in *; do convert -resize 640x480 $i `echo ${i%.*}_small.jpg`; done

By calling a variable as ${variable%something}, Bash chops the something off the end of the variable contents. So ${i%.*} removes the first dot from the right and everything after from the contents of $i (which in my example is a filename.) If you had more than one dot, you could do ${i.jpg} to only remove the .jpg extension from the name. Of course, the string match is case-sensitive.

There is a lot more information about "variable mangling" available in This LinuxJournal Article.