Skip to content

Instantly share code, notes, and snippets.

@MineRobber9000
Created March 15, 2026 07:16
Show Gist options
  • Select an option

  • Save MineRobber9000/a5d9bc08efc9b7aa395c9f6332cfd229 to your computer and use it in GitHub Desktop.

Select an option

Save MineRobber9000/a5d9bc08efc9b7aa395c9f6332cfd229 to your computer and use it in GitHub Desktop.
Batch rename tool using regex
from argparse import ArgumentParser
from re import compile as _re_compile
from pathlib import Path
from os import walk
from sys import exit
def iterdir(root, recursive = False):
if not recursive:
yield from Path(root).iterdir()
return
for dirpath, dirnames, filenames in walk(root):
for filename in filenames:
yield Path(dirname) / filename
def match_strategy(arg):
if arg=="full":
return "fullmatch"
elif arg=="start":
return "match"
elif arg in ("any","anywhere"):
return "search"
parser = ArgumentParser(description="Renames files in a directory by regex-based rules")
parser.add_argument("input_pattern",help="The pattern that matches the files you wish to rename.")
parser.add_argument("output",help="What you wish to rename these files to. Can use backreferences.")
parser.add_argument("-d","--dry-run",action="store_true",help="Show what files would be moved, and to where, but not actually do it.")
parser.add_argument("-r","--recursive",action="store_true",help="Recurse into subdirectories.")
parser.add_argument("-t","-root",dest="root",default=".",help="The root of the rename operation.")
parser.add_argument("-c","--on-conflict",choices=["error", "skip"],default="error",help="What to do if renaming a file would cause it to overwrite another file.")
parser.add_argument("-m","--match",choices=["full", "start", "any", "anywhere"],default="full",type=match_strategy,help="How to match the pattern against the filenames.")
args = parser.parse_args()
print(args)
pattern = _re_compile(args.input_pattern)
match = getattr(pattern, args.match)
for path in iterdir(args.root, args.recursive):
if not path.is_file(): continue
if not (m:=match(path.name)): continue
new_name = m.expand(args.output)
target = path.with_name(new_name)
if target.exists():
print(f"Cannot move {path} to {target} (target exists!)")
if args.on_conflict=="error":
exit(1)
print(f"{path} -> {target}")
if not args.dry_run: path.rename(target)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment