I have two scripts I use a lot when renaming large numbers of files. One does simple text search and replace, the other uses Python's regular expressions. (A note on style: when writing short scripts for me, which largely fit on a screen or two, I tend to use short variable names. I have a maths background, and so 'let g be a group and let x∈g' type language is natural to me, and this extends to coding. If writing something many pages long, and possibly spread over multiple files, then as is sensible, I start using descriptive variable names.) ## Examples ```bash # replace all spaces with underscores filesr " " "_" * # replace all runs of weird characters with an underscore filesrx '[^a-zA-Z0-9_\.-]+' '_' * # replace all instances of 'turnip' or 'tomato' with vegetable filesrx '(turnip|tomato)' 'vegetable' # for all files with runs of 3 digits in their filename, rename to e.g. file_4562.xyz filesrx '^.*(\d+).*' 'file_\1.xyz' ``` ## Code `filesr` — filename search and replace ```python #!/usr/bin/env python3 import sys,os import uuid,os.path args = sys.argv[1:] dryrun = os.getenv("D","n").lower() in "y" if len(args) < 3: print("filesr searchpat replpat ") sys.exit(1) s,r = tuple(args[:2]) files = args[2:] print(f"""filesr search: {s} replace with: {r}""") def rn(x,y): if not dryrun: os.rename(x,y) while True: t = str(uuid.uuid4()) if not os.path.exists(t): break print("Temp name {}".format(t)) for x in files: y = x.replace(s,r) xa = x.lower() ya = y.lower() if x == y: pass elif os.path.exists(y) and not xa == ya: print("{} already exists".format(y)) else: if xa == ya: print("Capitalisation issue") print(f"Using temp name {t}: {x} --> {y}") rn(x,t) rn(t,y) else: print(f"Rename {x} --> {y}") rn(x,y) ``` `filesrx` — filename regex search and replace ```python #!/usr/bin/env python3 import sys,os,re import uuid,os.path args = sys.argv[1:] dryrun = os.getenv("D","n").lower() == "y" case_insensitive = os.getenv("I","n").lower() == "y" def print_usage(): print(f"""{sys.argv[0].split('/')[-1]} [files...] # file regex search and replace set env variables I=y to set case insensiive, D=y to enable dry run """) def rn(x,y): if not dryrun: os.rename(x,y) def main(): if len(args) < 3: if len(args) == 2: print(f"No files specified") print_usage() exit(1) try: s,r = tuple(args[:2]) files = args[2:] except Exception: print_usage() exit(1) print(f"""{sys.argv[0]} # file regex search and replace regex: {s} replace with: {r} dry run: {dryrun} case insensitive: {case_insensitive} """) if case_insensitive: sr = re.compile(s,re.I) else: sr = re.compile(s) while True: t = str(uuid.uuid4()) if not os.path.exists(t): break print("Temp name {}".format(t)) for x in files: try: y = sr.sub(r,x) except: print(f"Regex {s} failed for file {x}") continue if x != y: print(f"{x} => {y}") xa = x.lower() ya = y.lower() if x == y: pass elif os.path.exists(y) and not xa == ya: print(f"{y} already exists") else: if xa == ya: print("Capitalisation issue") print(f"Using temp name {t}: {x} --> {y}") rn(x,t) rn(t,y) else: print(f"Rename {x} --> {y}") rn(x,y) if __name__ == "__main__": main() ```