lang/python/ PowerRename
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
# 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
#!/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 <files>")
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
#!/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]} <search regex> <replacement> [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()