Back

How to batch rename files in folders with Python

December 4, 2021 4 minute read
Files in folder before (left) and after (right)
Source: File names before and after

Although there are many tutorials on renaming files with Python, most don’t go into how to create flexible logic to tailor that batch file rename job to your needs. This is a situation I found myself in recently, a seemingly simple request to help rename a few hundred files in a folder. However, not all of the renaming followed a set pattern! Nor did it follow any real pattern at all, so using regex probably wasn’t going to help. This called for a custom script to help out a fellow engineer.

Problem

The problem given was that during an automation process hundreds of files had been produced but using the wrong names. These now all needed changing. The files names on the left needed to look like the file names on the right (this is a small sample but there were hundreds of files). As you can see it isn’t a straight up find and replace job, we will need some logic to match a search term to a replacement. For example, if the file name includes X then replace with Y. To trim the identifier at the beginning of the file name we’ll use string slicing.

Solution

This script makes use of the os module. We provide a folder path and then loop over all of the files within it, renaming with the replacements where the file name contains the search term.

renamer.py
import os

def rename_files(path):
    replacements = ["_dualforecast", "_narrative", "_pf1", "_summary", "_txn"]
    search_terms = ["CLAIM", "NARRATIVE", "PF1", "SUMMARY", "Txn"]
    count = 0
    
    for filename in os.listdir(path):
        file_path = os.path.join(path, filename)
        name, extension = os.path.splitext(filename)

        for i, term in enumerate(search_terms):
            if term in name:
                prefix = name[:11]
                postfix = replacements[i]
                new_name = os.path.join(path, prefix + postfix + extension)
                os.rename(file_path, new_name)
                continue

        count += 1
    
    print(f"{count} files in folder {path} were renamed.")


if __name__ == "__main__":
    rename_files(r"C:\\Users\\shedloadofcode\\Documents\\TestFolder")

Success! All of the files were renamed according to the logic applied and are now in the format like on the right side of the image shown earlier. This logic will also rename any subfolders in the directory too if you were wanting to rename folders rather than files. In this script I have also seperated the file name from the extension so if you were wanting to say change hundreds of txt files to csv format you can do that with just one change new_name = os.path.join(path, prefix + postfix + ".csv").

If you want to give this script a test drive, download the test folder, then extract the contents and place the directory 'TestFolder' in your Documents folder ensuring it has the name 'TestFolder'. Then update the path given to the rename_files function with your username before running 😄

Bonus: Recursive batch renaming

You might be thinking, but what if I have files within folders within folders? Do I have to run this in each folder one at a time? Hell no 😆 we can adapt the function to go through every subfolder and perform the rename operation in each recursively. Let's say we have folders A, B and C in the TestFolder directory.

Now let's take a look at the recursive function we'll run against the TestFolder directory path.

recursive-renamer.py
import os

def rename_files_recursively(root_path):
    replacements = ["_dualforecast", "_narrative", "_pf1", "_summary", "_txn"]
    search_terms = ["CLAIM", "NARRATIVE", "PF1", "SUMMARY", "Txn"]
    count = 0

    for path, subdirs, files in os.walk(root_path):
        for filename in files:
            file_path = os.path.join(path, filename)
            name, extension = os.path.splitext(filename)

            for i, term in enumerate(search_terms):
                if term in name:
                    prefix = name[:11]
                    postfix = replacements[i]
                    new_name = os.path.join(path, prefix + postfix + extension)
                    os.rename(file_path, new_name)
                    continue

            count += 1

    print(f"{count} files were renamed recursively from root {root_path}")


if __name__ == "__main__":
    rename_files_recursively(r"C:\\Users\\shedloadofcode\\Documents\\TestFolder")

Now we can see every file in every subfolder is renamed in one operation. This will also work to any folder tree depth.. subfolders within subfolders within subfolders.. everything. Isn't recursion wonderful? Here are folders A, B and C after the operation completes:

Adapting to your needs

There we are, two short adaptable and extendable functions that give us everything we need to get the job done! My colleague was certainly happy with the result, they said it worked like a dream. You can easily adapt these functions to your own needs by changing or adding to the conditional logic in the inner loop that processes each file name. Not only does this script apply to conditionally renaming files, but also conditionally deleting files. You could use os.remove(file_path) instead of the os.rename(file_path, new_name) we used.

Thanks very much for reading, this was a very short article covering how to effectively batch rename files in folders with Python. If you have any questions feel free to leave a comment 👍

If you enjoyed this article be sure to check out other articles on the site, you may be interested in: