There are several ways one can batch rename files in Linux. One of the possibilities is the linux command rename.
To rename files you have to supply a Perl expression. Using Perl expressions might be scary for beginners (because they look like someone hit his head on the keyboard), but they allow for complex renaming with a minimum of characters.
Although I won’t go into detail about Perl expressions here, I will try to make it a little easier for beginners to use them for batch renaming.
According to the man page of rename, this is the way to use rename:
rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]
If you have not worked with Perl expressions before, this might not be enough to get you started. So let me present you with the way one would probably use rename most of the time:
rename 's/OLD/NEW/' FILES
OLD is an expressions which describes a pattern in the name filenames. If rename can find this pattern in the name of a file, it will replace this part of the filename with what is defined as NEW. The files rename should rename are defined by FILES.
Let me provide you with two examples:
Example 1 – Replacing a single word/string
Let’s start with a very simple example: Imagine, you have a lot of images that are named
picture 1.jpg picture 2.jpg ...
and you would like to replace the word “picture” with the word “image”, so that the files will be named like this:
image 1.jpg image 2.jpg ...
As describes under usage, OLD represents the part that we want to replace. As we want to replace the word “picture”, in this example OLD will be “picture”.
And because NEW defines with what OLD is replaced with, in our example. We want the OLD(=”picture”) to be replaced with “image”, so here NEW=”image”.
And because we want to do this only for all the pictures which name starts with “picture” FILES will be “picture*.jpg”.
Therefore the general command
rename 's/OLD/NEW/' FILES
rename 's/picture/image/' picture*.jpg
It might have not been necessary for us to restrict this to the the files “picture*.jpg”. We might have just used *.jpg (all files in the current directory with the extension .jpg) or even * (all files in the current directory), because rename will only change the filename, if the pattern OLD (here: “picture”) is found in the filename. You have to be careful, though. A file with the name “just a picture.jpg” would have been renamed to “just a image.jpg”, because we told rename to replace “picture” with “image”.
Let’s go back to Example 1. One problem I mentioned is that running
rename 's/picture/image' *.jpg
to rename files like “picture 23.jpg” to “image 23.jpg” would also rename files like “just a picture.jpg” to “just a image.jpg”, because rename would find the word “picture” and replace it with “image”, although this is not what we intended.
We could prevent this by calling rename like this:
rename 's/picture/image' picture*.jpg
This would call rename only for the .jpg files starting with the word “picture”. But this is not really a solution, because files like “picture of a sunset.jpg” would still be renamed to “image of a sunset.jpg”.
To make sure that rename really does what we want it to do, we need to be very clear about what should be renamed. Because what we want is not to replace the word “picture” with the word “image” in every case, we want to replace the word “picture” with the word “image”, but only for the files which name consists of the word “picture”, then a space and then a number and then the extension “.jpg”.
This can be achieved with the following command:
rename 's/^picture( [0-9]*\.jpg)$/image$1/' *.jpg
This might look a little scary, but is a good example of what you can do with Perl expressions. Because this would only rename the desired files. Files like “my picture 11.jpg” or “picture 28 (beach).jpg” would not be renamed and in this example that is exactly what we want to do.
Let me go through the different parts of the expression above briefly, to give you an idea of how this works. Keep in mind that this just an example and not intended as a complete tutorial. I will just try to explain to you the various elements of this expression to show you some of the possibilities and to demystify them a little bit.
When you compare the command to the general form under “Usage”, you will see that in this case:
- OLD = ^picture( [0-9]*\.jpg)$
- NEW = image$1
- FILES = *.jpg
In this example OLD makes sure that only the desired files are renamed by defining the structure of what we are looking for exactly. This works, because OLD defines what should be renamed. That means that files where the pattern/structure defined by OLD can not be found will not be renamed. Therefore, OLD automatically works as a filter to make sure that only the desired files get renamed. The trick is to make sure that OLD and NEW reflect what you wish to do. Let’s dissect it:
Let’s ignore the “^” at the beginning, the “$” at the end, the parentheses and the “\” at the moment. This leaves the following:
This describes our basic structure. First, we have the word “picture”, then a space. [0-9] means any character from 0 to 9, which essentially means “a digit” and when putting a “*” after it, it means that there can be “any number of” digits. We need this, because we don’t know how many digits there will be. We can have files like “picture 7.jpg”, where there is only 1 digit or files like “picture 1432.jpg”, where he have four of them. So, “[0-9]*” stands for “any number of digits”, which just means: a number. And then we have “.jpg”, our extensions.
It is important to note that “[0-9]*” really means “any number of digits” and that “any number” could also mean 0. This means that the number is optional and a file named “picture .jpg” would also be renamed. In this example it probably would not make a real difference, but in general you need to be careful. If there really has to be a number and it can not be optional, you can use a “+” instead of a “*”, because “[0-9]+” means “at least one digit”. But because it will not be a problem in this case, we will keep the “*”.
Now, let’s add the parts we ignored:
The “.” is a special character which stand for “any character”. But in our pattern, we want to make clear that the filename ends with “.jpg”. But “.jpg” would be interpreted as “any character, then j, then p, then g”. Therefore a file like “picture 234Xjpg” would be renamed, because the . (which stand for “any character”) would be “X” in this case. But really want to make sure that the file ends with “.jpg” and therefore need to make it clear that the “.” really stand for “.” and not for “any character”. This can be done by escaping it with a “\”. Therefore, we need to write “\.jpg”.
The parentheses are added, because the pattern we are creating will be matching the complete filename. If we would run a command like this:
rename 's/^picture [0-9]*\ .jpg$/image/' *.jpg
A file like “picture 23.jgp” would be renamed to “image” and not to “image 23.jpg”. This is because our pattern “^picture [0-9]*\.jpg$” describes the whole filename. So the complete filename would be replace with “image”. But we just want to replace “picture” and keep the rest.
We can do this by telling rename that we want to keep everything after “picture”. While we can’t do this directly, we can put every after “picture” in parentheses and then later use this part to build our new filename, because everything within the parentheses will be saved accessible later as “$1″, so if we use the pattern
We can now see that the space, the number and the extension “.jpg” are within the parentheses and we can access this part as “$1″. When the filename is “picture 83.jpg”, $1 will therefore contain ” 83.jpg”. Then, when we define our replacement, we can tell rename to use “image$1″ as our replacement for the filename. Because $1 contains the space, the number and the extension, this would translate to “image 83.jpg”.
Now, what’s left are “^” and “$”. “^” stand for the beginning of the filename. This makes sure that files like “some picture 44.jpg” would not be renamed. This is because a pattern like “picture” means: find the word picture anywhere. Whereas “^picture” essentially means: find the word picture at the beginning of the input(=filename).
Similarly, “$” stand for the end of the input (here: filename). We use this to make sure that something like “picture 74.jpg.gz” does not get renamed.
Combining “^” and “$” therefore ensures that the filename only consists of the pattern we defined and there is nothing before “picture” and nothing after our “.jpg”.
Therefore, our final pattern is:
And the command to rename the files is, again:
rename 's/^picture [0-9]*\ .jpg$/image/' *.jpg
Example 4 – add a prefix to all filenames (added on 2012-05-20)
In case you want to add a prefix at the beginning of a filename, you can use this line:
rename ‘s/(.*)/PREFIX$1/’ FILES
Substitute PREFIX to whatever you want to put in front of the filename and substitute FILES for the files you want to rename (see Example 6 below for some examples)
If you run
rename ‘s/(.*)/foo_$1/’ *.txt
All the .txt files in the current directory will get an “foo_” in front of of their name. (So info.txt would be renamed to foo_info.txt, for example)
Example 5 – add a suffix to all filenames (added on 2012-05-20)
Adding a suffix at the end of a filename can be as simple as adding a prefix; you could simply run:
rename 's/(.*)/$1SUFFIX/' FILES
The problem is that this might not be what you expected, because the suffix will be added at the end of the filename, which also means after the suffix the file might already have to denote its type (e.g. “.txt”, “.tar”, “.jpg” etc. Running
rename 's/(.*)/$1boo/' info.tar
would rename the file “info.tar” to “info.tar.boo”. If that is what you want, you can use the line above, but if you would want to rename it to “infoboo.tar”, then you can use the following line:
rename 's/(.*)\.(.*)/$1SUFFIX.$2/' FILES
with this, running
rename 's/(.*)\.(.*)/$1boo.$2/' FILES
would rename “info.tar” to “infoboo.tar”.
Be aware that this will not work for files with suffixes that contain two dots (like “archive.tar.gz”).
Improvement 1 (Update 2012-05-22):
The fact that files like “archive.tar.gz” would be renamed as well and the result would certainly not be as hoped, we can try to improve the pattern above a little bit:
rename 's/^([^.]*)\.([^.]*)$/$1SUFFIX.$2/' FILES
This approach will only rename files that only contain a single dot and leave all other files alone.
Improvement 2 (Update 2012-05-22):
If you want to rename files with extensions like “.tar.gz” correctly, you can use the following approach:
rename 's/^([^.]*)\.(.*)$/$1SUFFIX.$2/' FILES
This will essentially add the suffix directly in front of the first dot. However, this approach will not work in case you have files that contain dots that are not supposed to be part of the file extension (in “some.great.file.txt”, the suffix “111″ would be added like this: “some111.great.file.txt”)
Example 6 – how to define which files to rename (added on 2012-05-20)
In the beginning I noted the general form of how to use rename:
rename 's/OLD/NEW/' FILES
I now want to give you some simple examples of what you can do with “FILES”, which tells rename which files it
should try to rename in the first place. This list is by no means complete. It just provides you with a few (hopefully useful) examples.
- to rename a single file just state its name. Example: backup.tar
- to rename several specific files just list all their names. Example: backup.tar mypicture.jpg asong.ogg
- to rename all files in the current directory just use “*” (without the “).
- to rename all files with a specific ending (e.g. .jpg) use “*ENDING”. Example: *.jpg
- to rename files with different endings, just list them all. Example: *.jpg *.jpeg *.mp3 *.txt *.ar
- to rename files that start with the same word/characters use “START*”. Example: my* old*
- to rename files that contain the same word/sequence of characters use “*WITHIN*”. Example: *good*
- you can combine all of those things. Example: my*.txt *boo*.jpg foo* test.tmp
I hope that this article succeeds in demonstrating how rename can be used to batch rename files (not in detail, but at least in pushing you in the right direction). And I also hope that while covering Perl expressions in detail is beyond the scope of this article, the second example gives you an idea of how powerful and useful they can be and why it can make sense to learn more about them.