Renaming files with the rename command
Renaming files is a basic and mundane task.
Fortunately, there are several tools to make it easier.
The Perl version of rename
available in Bash on many Linux distributions is especially powerful since it can utilize regular expressions.
Confirm which version(s) of rename you have available
As previously mentioned there can be more than one version of the rename
command on your system. So you’ll first want to confirm that you have the Perl version of rename installed and verify how the command is invoked on your system.
A warning
Before you begin, note that the rename command can rename files without additional prompting. And with regular expressions it is easy to misunderstand how the pattern will be applied. It’s a good idea to add the -n
options to the command to first see what changes would be made. Then, if you like the results, rerun the command without the -n argument. Consequently, all examples on this page will include the -n option. Just remove the -n argument when you’re ready to apply the changes.
The command form
The perl rename command has the form
rename [options] <expression> <file>
The command
man rename
provides details on how to use the rename command, but, like many man pages, it can be a bit overwhelming at first.
The command
tldr perl-rename
provides a shorter and more approachable introduction into the basic form of the rename command.
The Perl substitution operator
There are three regular expression operators in Perl.
This introduction will focus on s///
, the substitution operator, because it is useful for renaming, and won’t discuss the other operators.
Regular expressions can be a complex topic and this article seeks only to provide a starting point for using them to rename files. There is much more that can be accomplished with regular expressions than is shown here and a basic knowledge of their use is assumed.
Two resources I find helpful when working with regular expressions are this Regular Expressions Cheat Sheet and RegExr, an online tool to learn, build, and test regular expressions.
Example Setup: Creating a test directory
Before we start creating and deleting files, you may wish to first create a new directory in which to test these commands.
This will make it easier to see the effects of the changes we’re making and will reduce the risk of impacting files we don’t want to alter.
Example Scenario: Unhelpful podcast filenames
There are many wonderful podcasts available, but they often have unhelpful filenames that can make it difficult to manage the files directly.
For these examples, we’ll start by creating dummy files to test the commands on. We’ll utilize the file creation command built at the end of a previous post and alter it for our purposes.
To create ten example files that each include a random alphanumeric string enter the following:
Command
touch podcast$(shuf -erz -n $(shuf -e -n 1 {0..5}) {A..Z} {a..z} {0..9} | tr -d '\0'){01..10}-final.mp3
There are various outputs that are possible, but let’s say we now have the following set of files that are all in the same directory.
Result example
podcast08-final.mp3
podcast9mak01-final.mp3
podcastC02-final.mp3
podcastcYm10-final.mp3
podcastdzYKV05-final.mp3
podcastf09-final.mp3
podcastfUJsd04-final.mp3
podcasth0a06-final.mp3
podcastIE07-final.mp3
podcastU1jGb03-final.mp3
We’ll say the files are all related and are meant to be listened to sequentially, but they don’t have a consistent naming scheme so it’s not easy to tell how the files relate or the order in which they should be heard.
To fix that, we could rename them manually, but that’s not efficient. And while it’s doable for 10 files, it doesn’t scale to hundreds or thousands of files.
We can use the Perl rename command in Bash to rename them automatically.
Example 1: Adding a prefix
Let’s get started by adding a prefix to the files. We’ll add “ecn-” to the start of the filename to help us remember which podcast the files are from.
For now we’ll utilize the -n
option (as discussed above). And we’ll limit the scope of files effected by supplying the extension of files we want altered, *.mp3
in this example.
Command:
rename -n 's/^/ecn-/' podcast*.mp3
Let’s break down the elements of that command.
rename
- run the rename command.
-n
- invoke the “no action” option to print the file names to be renamed, but don’t actually rename them.
'...'
- - that is, the single quotes and the text within them - contain the pattern text that the rename command is is supposed to match and alter.
podcast*.mp3
- is the name pattern of the file(s) we want to modify. In this case, it should run the rename command against all files in the directory that start with “podcast”, end with “.mp3”, and have any number or type of characters inbetween.
Within the '...'
portion is an important element:
s/.../.../
- tells rename to use the substitution regular expression pattern, which should find text between the first and second forward slash and replace it with the text between the second and third forward slash.
^
- tells rename to find the beginning of each line of text.
ecn-
- tells rename to replace the matched segments with the literal string “ecn-”. In this case, since it is matching the beginning of each line, it will append “ecn-” to the beginning of each line.
In summary, this command looks at all files in the same directory with filenames that start with “podcast”, end with “.mp3”, and have any number or type of characters inbetween, searches for the beginning of the line (which will match all files), and appends the literal string “ecn-”. Since, the -n option is being used, the user will just see which files will be altered and how, without actually changing any files.
If you are happy with the expected changes you can run the command to alter the files by replacing -n
with -v
.
Example Result:
ecn-podcast08-final.mp3
ecn-podcast9mak01-final.mp3
ecn-podcastC02-final.mp3
ecn-podcastcYm10-final.mp3
ecn-podcastdzYKV05-final.mp3
ecn-podcastf09-final.mp3
ecn-podcastfUJsd04-final.mp3
ecn-podcasth0a06-final.mp3
ecn-podcastIE07-final.mp3
ecn-podcastU1jGb03-final.mp3
Example 2: Replacing part of a string
Let’s say that in seeing the altered files, we don’t find the change that helpful. Since this is for the fictional “Econ Hourly” podcast, we decide to replace the “ecn-podcast” with “econ-hourly_” to make the association clear.
Command:
rename -n 's/ecn-podcast/econ-hourly_/' ecn-podcast*.mp3
Most of the elements of this command are the same as those from the first example, but there are a few differences to consider.
ecn-podcast
is the pattern we are searching for - in this case the literal string “ecn-podcast”.
econ-hourly_
is the value we want to replace any matched strings with - in this case the literal string “econ-hourly_”.
ecn-podcast*.mp3
is the name pattern of the file(s) we want to modify. Since we altered the filenames in the previous example we need to update the command to reflect that. Otherwise, the command won’t match any files and therefore won’t change anything.
Example Result:
econ-hourly_08-final.mp3
econ-hourly_9mak01-final.mp3
econ-hourly_C02-final.mp3
econ-hourly_cYm10-final.mp3
econ-hourly_dzYKV05-final.mp3
econ-hourly_f09-final.mp3
econ-hourly_fUJsd04-final.mp3
econ-hourly_h0a06-final.mp3
econ-hourly_IE07-final.mp3
econ-hourly_U1jGb03-final.mp3
Example 3: Removing part of a string
Let’s remove the ‘-final’ suffix. It may be helpful to the podcast producer, but it’s not useful to us.
Command:
rename -n 's/-final//' econ-hourly_*.mp3
Let’s look at the elements that changed from the previous example.
-final
is the pattern we are searching for - in this case the literal string “-final”.
//
- that is, no value between the second and third forward slashes - is the value we want to replace any matched strings with - in this case an empty string, effectively deleting any matched strings.
econ-hourly_*.mp3
As the filename changes, we need to change this portion. We could use a more generalized name, like “*.mp3” but that risks matching files we don’t intend to match. It makes sense to be careful, especially when learning how to use a command.
Example Result:
econ-hourly_08.mp3
econ-hourly_9mak01.mp3
econ-hourly_C02.mp3
econ-hourly_cYm10.mp3
econ-hourly_dzYKV05.mp3
econ-hourly_f09.mp3
econ-hourly_fUJsd04.mp3
econ-hourly_h0a06.mp3
econ-hourly_IE07.mp3
econ-hourly_U1jGb03.mp3
Example 4: Rearranging the elements of the string
Now, we notice that the filename seems to have a portion right before the “.mp3” that has a two-digit number. Before that, there is an alphanumeric string of varying length.
For our purposes, let’s assume the two-digit number is an episode number and the alphanumeric string is something like an episode title or name of a guest to the show. For more consistent and legible names it would be helpful to move the episode number right after the show name and the alphanumeric string to the end of the file.
To accomplish that we’ll utilize the concept of capture groups for regular expressions.
Command:
rename -n 's/(econ-hourly_)(\w*)(\d{2})(.mp3)/$1$3_$2$4/' econ-hourly_*.mp3
Here is what changed from the previous example.
(econ-hourly_)(\w*)(\d{2})(.mp3)
is the regular expression pattern we are searching for. Let’s examine the elements of the regular expression more closely.
()
- parenthesis represent a capture group, which can be used in the replacement. Anything that matches the pattern in the capture group is stored in a variable numbered by the order of the opening parenthesis.
(econ-hourly_)
- the first capture group, which will match the literal string “econ-hourly_” and store the results in the $1
variable.
(\w*)
- the second capture group, which will match zero or more word characters (that is, anything in the set [A-Za-z0-9_]), and store the results in the $2
variable. \w
is the symbol for the word character class. *
is the quantifier representing zero or more of the preceding token. Taken together, \w*
will match a string of zero or more characters in the set [A-Za-z0-9_].
(\d{2})
- the third capture group, which will match exactly two digit characters (that is, anything in the set [0-9]), and store the results in the $3
variable. \d
is the symbol for the digit character class. {2}
is the quantifier representing exactly two of the preceding token. Taken together, \d{2}
will match a string of exactly two characters in the set [0-9].
(.mp3)
- the fourth capture group, which will match the literal string “.mp3” and store the results in the $4
variable.
$1$3_$2$4
is the value we want to replace any matched strings with. This will replace the matched pattern with the following elements:
- the string found in capture group 1
- the string found in capture group 3
- the literal string “_”
- the string found in capture group 2
- the string found in capture group 4
This has the effect of rearranging the string portions that match the 4 patterns we specified and adding an underscore.
Example Result:
econ-hourly_01_9mak.mp3
econ-hourly_02_C.mp3
econ-hourly_03_U1jGb.mp3
econ-hourly_04_fUJsd.mp3
econ-hourly_05_dzYKV.mp3
econ-hourly_06_h0a.mp3
econ-hourly_07_IE.mp3
econ-hourly_08_.mp3
econ-hourly_09_f.mp3
econ-hourly_10_cYm.mp3
Conclusion
This is only an introduction into the use of the rename command. It is powerful and there is much more you can do.
There is much room for improvement in these example commands, and if you find yourself repeating these steps, you could simplify and combine them, or include them in a script to automate the process. Just be careful not to be too clever in your efforts or you might give yourself the opportunity to rediscover Kernighan’s Law anew.