So, you’ve procured a number of files that represent a pre-recorded television series and they are typically named something like this:
MyTVShow.Original.S01E01-720p.HDTV.x264-ImAwesome.mkv
MyTVShow.Original.S01E02-720p.HDTV.x264-ImAwesome.mkv
MyTVShow.Original.S01E03-720p.HDTV.x264-ImAwesome.mkv
MyTVShow.Original.S01E04-720p.HDTV.x264-ImAwesome.mkv
You’d like to rename them to look something like this instead:
MyTVShow S01E01.mkv
MyTVShow S01E02.mkv
MyTVShow S01E03.mkv
MyTVShow S01E04.mkv
Normally you’d tediously edit each filename and rename them manually, but to do so individually across a large folder will take a long time. Surely there’s a way to rename them all in a more convenient manner?
There certainly is! And with just one command too…
One command? How can you possibly do that, you ask? Well, Linux commands generally have the ability to accept a regular or Perl expression to allow for complex matching tasks, simplifying your work, and we will utilise that here with the rename command’s ability to parse Perl expressions.
Note: As I understand it, only Debian-based distros such as Ubuntu carry the “rename” command as part of the default command set. Other distros may require you to add the command binary to your system.
The task in this case is to take a string to match on, in this case “MyTVShow.Original.”, take a wildcard match of the “SxxEyy” part (where “xx” and “yy” are any numeric characters), ignore everything after that and then create a new string for the filename that is formatted as “MyTVShow SxxEyy.mkv” and replace “xx” and “yy” with the Season and Episode number picked up in the wildcard match.
And even better than that, we will write this in such a way that we can support any file extension so it doesn’t matter if the folder contains “.mkv” or “.avi” or “.mp4″ files, they will all be preserved in the rename.
This is the command you need:
rename -n 's/MyTVShow\.Original\.[Ss](\d{2})[Ee](\d{2}).+(\.\D{3})/MyTVShow\ S$1E$2$3/' *
When you run it, you will see output as follows:
$ rename -n 's/MyTVShow\.Original\.[Ss](\d{2})[Ee](\d{2}).+(\.\D{3})/MyTVShow\ S$1E$2$3/' *
MyTVShow.Original.S01E01-720p.HDTV.x264-ImAwesome.mkv renamed as MyTVShow S01E01.mkv
MyTVShow.Original.S01E02-720p.HDTV.x264-ImAwesome.mkv renamed as MyTVShow S01E02.mkv
MyTVShow.Original.S01E03-720p.HDTV.x264-ImAwesome.mkv renamed as MyTVShow S01E03.mkv
MyTVShow.Original.S01E04-720p.HDTV.x264-ImAwesome.mkv renamed as MyTVShow S01E04.mkv
But hang on, when I list my files, they’ve still got the old names! What gives?
The “-n” parameter tells the rename command not to actually action any rename, but show you what it would have acted on – good for testing just in case you made a mistake in your match criteria. Once you are ready to commit the rename, either remove the “-n” parameter or if you’d like to see what the rename command is doing, replace it with “-v” for verbose output instead (it’s the same as “-n”‘s output).
So exactly how does this command work? Let’s break it down a bit:
rename -n ‘s/MyTVShow\.Original\.[Ss](\d{2})[Ee](\d{2}).+(\.\D{3})/MyTVShow\ S$1E$2$3/’ *
- The first part specifies the rename command, the parameters to use and specifies the starting string we need to match on. You will notice that there are backslashes before the full stops. This is needed because the full stop character has other functions in an expression and so to specify it as a literal character, we need to “escape” out of the expression mode into “literal” mode, and that is facilitated by the blackslash. The character that follows the backslash is to be taken literally as part of the string we are constructing. If you wanted to literally specify a backslash character, for example, you’d have to specify a double backslash, ie: “\\”.
rename -n ‘s/MyTVShow\.Original\.[Ss](\d{2})[Ee](\d{2}).+(\.\D{3})/MyTVShow\ S$1E$2$3/’ *
- This part matches the “SxxEyy” part of the filename. This is not a literal string in this case because we need to dynamically cater for the different Season and Episode numbers in each filename. In addition to that, Linux filenames are case-sensitive, so we also need to consider that the “S” and “E” parts could be upper or lowercase, so we start with “[Ss]” which means “match either a capital ‘S’ or a lowercase ‘s’ please”, then we specify that we wish to wildcard the next two digits by specifying “(\d{2})”. The “\d” means to match any numerical digit and is essentially a shorthand version of “[0-9]” (it also matches other language numerical digits beyond the English 0-9, but I digress). The “{2}” part means apply that digit match to the next two characters, so we match on “01” or “02” or “03”, etc.We apply the same process to the “Eyy” part of the string, again matching either a capital “E” or a lowercase “e” followed by any two numerical digits.Finally, we accept the remainder of the filename up to the filename extension with the “.” part (because we don’t care what’s here) and explicitly wildcard match the extension with the “+(\.\D{3})” part, which allows us to match any three character file extension (not just numbers), for example “.mkv”, “.MKV”, “.avi”, “.mpg”, etc, however it will NOT match “.mpeg” or “.jpeg” or “.myfilextension” because those are larger than three character extensions that while they form a part of perfectly legal filenames, they are also very uncommon. In this case we will ignore them and assume that we’ll only ever deal with three character file extensions.
rename -n ‘s/MyTVShow\.Original\.[Ss](\d{2})[Ee](\d{2}).+(\.\D{3})/MyTVShow\ S$1E$2$3/’ *
- Now that we’ve specified our matching criteria, what do we do when we’ve found that match? We need to tell the rename command what we’re going to be renaming it to. The first forward slash means we’ve finished specifying our match criteria and are now specifying our rename string and it starts off with “MyTVShow” followed by an escape to be able to specify a space before the “SxxEyy” bit. We then specify the “SxxEyy” bit as “S$1E$2″.Now you didn’t know this, but in the previous matching criteria, the digit wildcard matches were automatically stored as variables because they were surrounded by parenthesis “(” and “”. Variables generated start at $1 and continue up as $2, $3, etc. You can now specify those variables as part of your destination filename and in this case, the Season number that was wildcard matched from the original filename is now specified as the first variable $1 in your destination filename, thus if “03” was in the original filename as the Season number, you can now write “03” as part of your destination filename. Ditto the Episode number as variable $2.Finally, we end the destination string with a straight up “$3″ that will specify the third variable we created which is the filename extension picked up in the wildcard match, which in our tutorial example will be “.mkv”. The beauty of this is that if you had multiple files with different file extensions, those extensions will be completely preserved.
rename -n ‘s/MyTVShow\.Original\.[Ss](\d{2})[Ee](\d{2}).+(\.\D{3})/MyTVShow\ S$1E$2$3/’ *
- And finally, we specify which files the rename command will be applied to as a whole. In this case because we have an expression to do the matching, we don’t need to use traditional filename matching, so we just specify an asterisk to apply to “all files” because any file that does not match the search expression will be ignored.
Optional: Getting slightly trickier, but for good reason…
Let’s say you deal with a lot of these files that you have to rename with different names on a regular basis. While the above tutorial has saved you a fair bit of time, at the moment you’re always having to copy and paste the command down and then modifying it to suit the filename strings you are changing from and to, remembering to escape certain characters so that they are processed properly like the full stops. We can make this process even more convenient by using a Bash script to allow us to simply specify a command followed by old and new strings only and not have to worry about escape characters.
- Create a new file using your text editor (you can name it anything you like and it does not have to have “.sh” on the end):
$ sudo nano /usr/bin/fixfilenames.sh
- Type or copy and paste in the following:
#!/bin/bash
# =============================================================
# Bulk rename TV series files. Written by HyRax, January 2014
# ==============================================================
if [ $# == 0 ]; then
echo ""
echo "Usage: $0 OLDNAME NEWNAME"
echo ""
echo " Eg: If the original filename is 'MyTVShow.Original.S01E01-720p.HDTV.ImAwesome.mkv' then"
echo " specify the command as '$0 MyTVShow.Original. MyTVShow' which will rename"
echo " all the files into 'MyTVShow SxxEyy.mkv' format. Note that a space is assumed as wanted between"
echo " the new name and the SxxEyy part. The Season and Episode numbers along with the file extensions"
echo " will be preserved in each rename."
echo ""
exit
fi
cmd="rename -v 's/$1[Ss](\d{2})[Ee](\d{2}).+(\.\D{3})/$2 S\$1E\$2\$3/' *"
echo ""
echo "Renaming files... (Renamed files will be listed below. Nothing listed means nothing actioned!)"
eval $cmd
echo "Done."
- Save your changes by pressing CTRL+X, then Y and then Enter.
- Now let’s make the new script executable:
$ sudo chmod +x /usr/bin/fixfilenames.sh
- Now you can rename your files as follows (using the tutorial’s filename example):
$ fixfilenames.sh MyTVShow.Original. MyTVShow
- List your directory and you will see all your files renamed successfully!
Pat yourself on the back. You’re done. If you’d like to explore more about expressions and what they can do, there are dozens of general tutorials around on the web which will easily teach you how to modify your expression to cover even more complex matches should you have that need.