Renaming Files with the rename Command (the Perl Version) in Bash

Published: 2022 March 02

system administration Linux Bash shell command regular expressions

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:

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.

Copying Directory Structure With a Bash Script - With Help From ChatGPT AI

Published: 2024 January 22

Setting Up a Raspberry Pi as a Linux Print Server with CUPS

Published: 2024 January 19

Setting Up a Raspberry Pi Zero 2 W with Ubuntu Server

Published: 2024 January 04