5Sep2007

Ever want to change the file extension for a group of files in one fell swoop? Me too. If you are using a unix-like system (Linux, Solaris, OS X, etc) then this is extremely easy using a Bash script. If you are on a Windows system then stop everything right now and go install the Cygwin environment.

The task at hand is actually pretty easy and can be done as a one liner, but I thought I’d create a more general purpose script. That way I can just use my script the next time I need to rename some files.

OLDEXT=${2/#.}
NEWEXT=${3/#.}

find "${1}" -iname "*.${OLDEXT}" |
while read F
do
  NEWFILE="${F/%${OLDEXT}/${NEWEXT}}"
  echo "mv \"${F}\" \"${NEWFILE}\""
  mv -f "${F}" "${NEWFILE}"
done

The numbers 1, 2 and 3 represent command-line arguments. You’ll see above the first thing I do is store the 2nd argument as the old extension and strip off any leading “dot”. I do the same with the 3rd argument storing it as the new extension. Next I do a find with the first argument being the search directory. Notice the iname option which means it will do a case insensitive name match. I pipe the results of the find into a while loop, calculate the new filename and rename/move the file. That’s it! Below is the full script file which includes a usage statement and some pretty comments.

Note: if the file here doesn’t work for you then you may simply need to retype it. I created the file on a Cygwin environment in Windows and sometimes when you move files from Windows over to a Unix system there are special characters which prevent it from being executed.



6 Comments

1

Thanks for that, Jonathan

Is there a simple way to adapt the script to accept multiple incoming extensions all at once (say, psd, tif, jpg)

I’m tying it in with some “sips” usgae on OS X to batch convert entire directory trees to small jpegs.

Thanks, Ben



Bash is very powerful and you can basically tell it to do whatever you want… so sure!

You could try playing with the find syntax. I was able to get find to get a listing of files with it’s -iregex option, which uses regular expressions to find the files.

find "${1}" -regextype "posix-extended" -iregex ".*.(psd|tif|jpg)"

You could hard code the extensions in your find statement or you could pass them in on the command line if you liked.


3

Thanks Jonathan, you’ve saved my day.
I’ve adapted your script to ‘svn mv’ files by changing extension.
Honestly, I didn’t know the /# /% syntax inside brackets!


4

In windows there’s no need for Cygwin, this is one of the extremely rare occasions that cmd.exe can actually do something well:

move *.old *.new

Works with copy as well.


5

lol – Well, certainly I’m not saying that there is a “need” for Cygwin in Windows, per se. However, I personally am more comfortable in *nix land as far as the command prompt goes. Does Windows have a built regular expression parser (ie Sed)? Nope.

So basically it comes down to preference. If you like doing things the Windows way then that’s great. If you like Linux/Unix then you can have that too! Thanks for taking the time to comment.


6

i need some help with this program. i ran your script in Unix Bash but it is telling me that the -iname is a bad option, do u know why, i am using the bash in Unix for enaxple ia put the filename on the command followed by three argument.
eg . please help. this is my program design.

Write a bash script that will change the extension of a list of files. This script should accept three or more arguments, according to the following pattern:
chngext …
It should then rename all the files in the list of filenames on the command line that end with the suffix ‘oldext’, replacing ‘oldext’ with ‘newext’. The script should print a message for each file named on the command line, indicating either that it is changing the file name (“… from … to …”) or that the file name did not include the specified suffix.


 




Leave a comment