Bulk Rename Files in Python with Regex Replacement

Renames every file in a directory by applying a regex substitution to its filename using Python's stdlib re and pathlib.

Easy Python 3.4+ Aug 9, 2026 Automation & scripting 16 views 0 copies

Python code

29 lines
Python 3.4+
import re
from pathlib import Path

def bulk_rename_regex(directory, pattern, replacement):
    path = Path(directory)
    renamed = []
    for file in path.iterdir():
        if file.is_file():
            new_name = re.sub(pattern, replacement, file.name)
            if new_name != file.name:
                new_path = file.with_name(new_name)
                file.rename(new_path)
                renamed.append((file.name, new_name))
    return renamed

if __name__ == "__main__":
    import tempfile
    import os

    with tempfile.TemporaryDirectory() as tmpdir:
        for name in ["file1.txt", "file2.txt", "photo1.jpg", "photo2.jpg"]:
            Path(tmpdir, name).touch()

        result = bulk_rename_regex(tmpdir, r"\d+", "X")
        for old, new in result:
            print(f"{old} -> {new}")

        print("---")
        print(sorted(f.name for f in Path(tmpdir).iterdir()))

Output

stdout
file1.txt -> fileX.txt
file2.txt -> fileX.txt
photo1.jpg -> photoX.jpg
photo2.jpg -> photoX.jpg
---
['fileX.txt', 'photoX.jpg']

How it works

The function iterates over all entries in the given directory using Path.iterdir(), filtering only regular files with is_file() to avoid renaming folders. For each file, re.sub() applies the regex pattern to the filename only (not the full path) and returns a possibly new name. If the new name differs, it constructs a new Path with with_name() and calls rename() to perform the filesystem operation. The list of old and new names is collected and returned, so callers can log or verify what was renamed after the loop finishes. Because the script uses temporary files, the output shows exactly which files matched the digit pattern and what they became, plus the final directory listing.

Common mistakes

  • Calling `rename()` on a Path that still points to the old location—you must use `with_name()` or `parent / new_name`.
  • Using a pattern that also matches the directory path when applying `re.sub` to the full `str(file)` instead of `file.name`.
  • Forgetting to check `is_file()` so directories or symlinks get renamed accidentally.
  • Not collecting results before printing, so the `rename()` call may overwrite existing files silently.

Variations

  1. Use `path.glob('*')` instead of `iterdir()` if you only want files matching a given wildcard pattern.
  2. Add a dry-run mode that prints proposed renames without actually renaming, by skipping `file.rename(new_path)`.

Real-world use cases

  • Normalizing exported files from a camera or download folder to replace timestamps like IMG_20230101 with readable labels.
  • Cleaning up log files by removing date stamps or trailing version numbers so backups are consistent.
  • Migrating a codebase's asset names by stripping spaces and special characters into snake_case for CI pipelines.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Automation & scripting

Related tutorials and quizzes for this topic.