How to batch rename files with "variables"? [duplicate]

I use xmbc to view my tv shows. Before I began using xmbc, I batch downloaded the first few seasons of "Bleach". What can I say, I'm an anime fan ;-). These are named: "bleachxx.mp4" where xx is the episode number in respect to the whole series, not to the season. so "bleach21.mp4" is the 1st episode of the second season and 21st overall. The files themselves are, however, divided into their own season folders.

I know you can use the "rename" command to batch rename files. After much tinkering with it using this guide: http://tips.webdesign10.com/how-to-bulk-rename-files-in-linux-in-the-terminal I got this command:

rename -n 's/.*(\d{2}).*$/Bleach S0XE$1/' *

The problem is that the command will rename all the files into "Bleach S0XExx" but because the files have the overall file numbers, bleach52.mp4 --> 'Bleach S03E52.mp4' when there obviously aren't 52 episodes in season 3.

I would like to know, then, if there is any way to apply mathematical operations to the file renaming. This would solve the problem as I could subtract The number of episodes in the previous seasons by the overall number and essentially get the season number.

Example: If there are 20 episodes in season 1, then 25-20=5 so the 25th episode is the 5th of season 2 and renaming would carry out as normal.

So, is there anyway to change the values of renaming by applying math operations?

P.S. I'm sorry for the long explanation but I wasn't sure how to or if my question would be clear without it.


If you're dedicated enough to tinker with regular expressions (in the example you're provided) then I suggest just to go one step farther and write a small script - say, in Python. This way you'll be able to perform absolutely any transformations to file names.

I would estimate the python script would be no longer than 15-20 lines long so it's definitely not a huge task. Using just regexps, as you're trying, is much more limited.

Here's my take on such script:

#!/usr/bin/python
import os,re

files = os.listdir('.')

SEASONS = (
 (1, 1, 3), # the format is - season number, first episode, last episode
 (2, 50,52),
 (3, 53,55),
 (4, 56,99),
)

for f in files:
    # skip all files which are not .mp4
    if not f.endswith(".mp4"):
        continue

    # find the first number in the filename
    matches = re.findall("\d+", f)
    if not len(matches):
       print "skipping", f
    num = int(matches[0])

    for season in SEASONS:
        if num <= season[2]:
            season_num = season[0]
            ep_num = num - season[1] + 1
            new_file_name = "BleachS%02dE%02d.mp4" % (season_num, ep_num)
            # This is for testing
            print "%s ==> %s" % (f, new_file_name)
            # Uncomment the following when you're satisfied with the test runs
            # os.rename(f, new_file_name)
            break

print "Done"

It looks like I under-estimated the script size (it's 36 lines atm), though I'm sure if you go to stackoverflow with this code, you'll get many suggestions which are much more elegant

And just because I said it can be done in 15 lines... the following is 20 lines, 5 of which is configuration :P

#!/usr/bin/python
import os, re, glob

SEASONS = (
 {'num':1, 'first':1, 'last':3}, # the format is - season number, first episode, last episode
 {'num':2, 'first':50, 'last':52},
 {'num':3, 'first':53, 'last':55},
 {'num':4, 'first':56, 'last':99},
)

files = glob.glob('bleach*.mp4')
for f in files:
    num = int(re.findall("\d+", f)[0])  # find the first number in the filename
    for season in SEASONS:
        if num > season['last']: continue
        new_file_name = "BleachS%02dE%02d.mp4" % (season['num'], num - season['first'] + 1)
        print "%s ==> %s" % (f, new_file_name) # This is for testing
        # os.rename(f, new_file_name) # Uncomment this when you're satisfied with the test runs
        break

I wrote you a python script

import sys
import os
import glob
import re

def rename():
    episode_counts = (0, 20, 41, 63)
    episode_pairs = []
    for index, num in enumerate(episode_counts):
        if index < len(episode_counts) - 1:
            episode_pairs.append((num, episode_counts[index+1]))

    episodes = glob.glob(os.path.join(sys.argv[1], '*'))

    for episode in episodes:
        match = re.search('.*(\d{2}).*$', os.path.basename(episode))
        episode_num = match.group(1)

        for season, pair in enumerate(episode_pairs):
            if int(episode_num) in range(pair[0]+1, pair[1]+1):
                dirname = os.path.dirname(episode)
                path = os.path.join(dirname, 'Bleach S{0}E{1}'.format(season+1, episode_num))
                os.rename(episode, path)

if __name__ == "__main__":
    rename()

I'm really new to python (which is partly why I wrote this, for practice), so it's probably not the best script in the world. But I tried it on a few test files and it seems to work.

Just edit the line near the top episode_counts = ... to the last episode numbers for a season. I put in the first three from this page.

Save the code as something like episode_renamer.py and use it with python episode_renamer.py /path/to/episodes/.


There is a file manager called Thunar available in the repository which has a bulk rename option.

See this site for more information: http://thunar.xfce.org/pwiki/documentation/bulk_renamer

You can install thunar in the Software Center or on the command line with:

sudo apt-get install thunar

There are other ways of doing this in bash, or by writing some code, but a graphical tool will probably get you what you want faster.


I'm developing a cross-platform desktop application that lets you rename a set of files from a specified pattern to another one. User can specify both of the patterns.

You can download it from this link (it's called: file-renamer-swt). And here is the project main site.