Dup Ver Goto 📝

PowerRename

PT2/lang/python/fs does not exist
To
265 lines, 776 words, 6601 chars Page 'PowerRename' does not exist.

I have some 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'

# Apply tr to filename
# change all x's to y's and all a's to b's
filetr xy ab ...

Code

These scripts use the filesr_common.py module at the bottom.

filesr

#!/usr/bin/env python3

import sys,os,re
import uuid,os.path
from filesr_common import Renamer

args = sys.argv[1:]

overwrite = False
verbose = False
if os.getenv("OVERWRITE") in ["y","Y"]:
  overwrite = True
if os.getenv("VERBOSE") in ["y","Y"]:
  verbose = True

forreal = True
if os.getenv("DRYRUN") is not None and os.getenv("DRYRUN") not in ["n","N"]:
    forreal = False
elif os.getenv("D") is not None and os.getenv("D") not in ["n","N"]:
    forreal = False

if len(args) < 3:
    print("filesr searchpat replpat <files>")
    if len(args) == 2:
      print("(did you forget to specify files)")
    sys.exit(1)

s,r = tuple(args[:2])
filenames = args[2:]
print(f"""filesr
      search: {s}
replace with: {r}""")

renner = Renamer(forreal=forreal,overwrite=overwrite,verbose=verbose)
renner.sr(s,r)
renner.process(filenames)

filesrd

#!/usr/bin/env python3

import sys,os
import uuid,os.path

args = sys.argv[1:]

overwrite = False
if os.getenv("OVERWRITE") in ["y","Y"]:
  overwrite = True

forreal = True
if os.getenv("DRYRUN") is not None and os.getenv("DRYRUN") not in ["n","N"]:
    forreal = False
elif os.getenv("D") is not None and os.getenv("D") not in ["n","N"]:
    forreal = False

if len(args) < 2:
    print("filesrd chars_to_delete <files>")
    sys.exit(1)

chars_to_delete = args[0]
files = args[1:]
print(f"""filesr
      chars_to_delete: {chars_to_delete}""")

def rn(x,y):
    if forreal:
      if os.path.exists(y):
        print(f"{y} exists")
        if overwrite:
          try:
            print(f"Overwritten {y}")
            os.rename(x,y)
          except IsADirectoryError:
            print(f"{y} is a directory")
      else:
        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
    for c in chars_to_delete:
      y = y.replace(c,"")
    if x == y:
        pass
    elif os.path.exists(y):
        print("{} already exists".format(y))
    else:
        xa = x.lower()
        ya = y.lower()
        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

#!/usr/bin/env python3

import sys,os,re
import uuid,os.path
from filesr_common import Renamer

args = sys.argv[1:]

overwrite = False
verbose = False
if os.getenv("OVERWRITE") in ["y","Y"]:
  overwrite = True
if os.getenv("VERBOSE") in ["y","Y"]:
  verbose = True

forreal = True
if os.getenv("DRYRUN") is not None and os.getenv("DRYRUN") not in ["n","N"]:
    forreal = False
elif os.getenv("D") is not None and os.getenv("D") not in ["n","N"]:
    forreal = False

if len(args) < 3:
    print("filesrx searchpat replpat <files>")
    print("  searchpad is regex")
    if len(args) == 2:
      print("(did you forget to specify files)")
    sys.exit(1)

s,r = tuple(args[:2])
filenames = args[2:]
print(f"""filesrx
       regex: {s}
replace with: {r}""")

renner = Renamer(forreal=forreal,overwrite=overwrite,verbose=verbose)
renner.srx(s,r)
renner.process(filenames)

filesrxd

#!/bin/bash
export DRYRUN=y
filesrx "$@" 

filesr_common.py

#!/usr/bin/env python3

import sys,os,re
import uuid,os.path
from icecream import ic; ic.configureOutput(includeContext=True)

class Renamer:
  def __init__(self,forreal = False, overwrite = False, verbose = False):
    self.renner = None
    self.forreal = forreal
    self.verbose = verbose
    self.overwrite = overwrite

  def sr(self,search,replacement):
    def filesr(filename):
      return filename.replace(search,replacement)
    self.renner = filesr

  def srx(self,search,replacement):
    regex = re.compile(search)
    def filesr(filename):
      try:
        m = regex.search(filename)
        if m is None and self.verbose:
          print(f"File {filename} does not match {s}")
        return regex.sub(replacement,filename)
      except Exception as e:
        ic(f"Regex {search} failed for file {filename}",e)
        return None
    self.renner = filesr

  def tr(self,search,replacement):
    trans = str.maketrans(search,replacement)
    def filesr(filename):
      return filename.translate(trans)
    self.renner = filesr

  def process(self,filenames):
    while True:
        t = str(uuid.uuid4())
        if not os.path.exists(t):
            break
    print("Temp name {}".format(t))
    temp_name = t
    for x in filenames:
      y = self.renner(x)
      if y is None:
        print(f"replacment func failed for {x}")
        continue
      if x == y:
        pass
      elif os.path.exists(y):
        sx = os.stat(x)
        sy = os.stat(y)
        if not sx.st_ino == sy.st_ino:
          print("{} already exists".format(y))
        else: # x and y are the same file
          print("Capitalisation issue")
          print(f"Using temp name {t}: {x} --> {y}")
          self.rn(x,t)
          self.rn(t,y)
      else:
          print(f"Rename {x} --> {y}")
          self.rn(x,y)

  def rn(self,x,y):
    if x == y:
      print(f"No change in {x}")
      return
    if self.forreal:
      if os.path.exists(y):
        print(f"{y} exists")
      if self.overwrite:
        try:
          print(f"Overwritten {y}")
          os.rename(x,y)
        except IsADirectoryError:
          print(f"{y} is a directory")
      else:
        os.rename(x,y)