Posted by Steve on Wed 1 Jun 2005 at 05:29
Renaming multiple files seems to be a problem which many newcomers to shell scripting, or administration, have problems with. But once you've done it a few times the actual solutions are very simple.
There are many cases where you might have a large number of files to rename en masse, for example files which are output from a given script or tool. Or files that must be renamed to be uploaded to a web-host.
How you rename the files mostly depends on which tools you have available, and which shell you're using.
The way I tend to rename large numbers of files is the same way that I tend do any job which requires running the same command on a number of files - I use the looping facility within the bash shell.
For example lets assume you have several files in a directory a.JPG, b.JPG, c.JPG and d.JPG then you can work with each one as follows:
skx@lappy:~$ for i in *.JPG; do echo $i; done a.JPG b.JPG c.JPG d.JPG
This command has worked with each file which matches the pattern "*.JPG", and runs a command on each file - in this case it's "echo $i".
Obviously the command which we're running, here it is echo, can be replaced with other commands.
If we used to use this style of command to rename each of the files to lowercase their extensions we have two possible approaches:
The bash shell has a notion of text substitutions which is very powerful, and something that can be very useful to know about so we'll cover that first.
The simplest example I can think of is to strip the extension. For a filename which is stored in the shell variable $i you can strip a known extension with this:
skx@lappy:~$ i=a.JPG
skx@lappy:~$ echo $i
a.JPG
skx@lappy:~$ echo ${i/.JPG/}
a
Here we've used the substitution operation to strip the ".JPG" from the end of our variable - we can plug this into the loop we showed earlier to force a rename:
skx@lappy:~$ ls
a.JPG b.JPG c.JPG d.JPG
skx@lappy:~$ for i in *.JPG; do mv "$i" "${i/.JPG}".jpg; done
skx@lappy:~$ ls
a.jpg b.jpg c.jpg d.jpg
(The "quotes" around the arguments to the mv command are useful if you're ever working with files which contain strange characters, or spaces, in their names).
This is the basic way that you can rename files with bash - use a loop to work on each file, then use the built-in substituion operations to strip or add to each name in turn.
The other approach is to use basename to manipulate filenames. basename is a standard command which allows you to strip suffixes from filenames:
skx@lappy:~$ basename c.jpg .jpg c skx@lappy:~$ basename c.jpg pg c.j
Here you can see that the command just returns the filename you've specified with the second argument removed from it.
This can be plugged into our loop like this:
skx@lappy:~$ ls a.jpg b.jpg c.jpg d.jpg skx@lappy:~$ for i in *.jpg; do mv "$i" "`basename $i .jpg`.JPG"; done skx@lappy:~$ ls a.JPG b.JPG c.JPG d.JPGUsing Specialised Commands
Instead of remembering how to run these loops over files with bash, you can instead rename files en masse with specialised renaming commands.
A simple one is the rename command which is included with the Debian perl package and almost certainly available to you already.
The rename command allows you to rename files with full perl expressions, in a simple manner.
For example our preceeding example of changing the extension can be achieved with:
skx@lappy:~$ rename 's/\.JPG/\.jpg/' *.JPGWe can also, for example, strip spaces from filenames with this:
skx@lappy:~$ rename 's/ //' *.JPGRenaming files from upper to lower case can be a simple job:
skx@lappy:~$ rename 'y/A-Z/a-z/' *There are also other specialised commands which you can locate with the apt-cache command, such as mmv and mrename.
This article can be found online at the Debian Administration website at the following bookmarkable URL:
This article is copyright 2005 Steve - please ask for permission to republish or translate.