This is my little bulk file renaming tool. I use this all the time. Inspired by the venerable rename Perl script, my version uses Python regular expressions and focuses on safety.

That's not just important, it's super-duper important! Bulk renaming is dangerous enough, but add regular expressions into the mix and It's all too easy to shoot yourself in the foot.


Basic usage is simple. If you've ever used Python's re.sub() function you're 90% of the way there! SEARCH is a regular expression and REPLACE is a literal (mostly). With no other arguments a dry-run is performed.

$ ls
foodofgods_01_wells_64kb.mp3  foodofgods_07_wells_64kb.mp3
foodofgods_02_wells_64kb.mp3  foodofgods_08_wells_64kb.mp3
foodofgods_03_wells_64kb.mp3  foodofgods_09_wells_64kb.mp3
foodofgods_04_wells_64kb.mp3  foodofgods_10_wells_64kb.mp3
foodofgods_05_wells_64kb.mp3  foodofgods_11_wells_64kb.mp3
foodofgods_06_wells_64kb.mp3  foodofgods_12_wells_64kb.mp3

Renaming Chapters

I enjoy listening to audio books while walking my dog. A great place to get and share public-domain books is LibriVox. This is a copy of H.G. Wells' 1904 book The Food of the Gods and How It Came to Earth read by a volunteer. I'd like to rename the files:

$ 'foodofgods_(\d\d)_wells_64kb' '\1. Food of the Gods'
01. Food of the Gods.mp3
02. Food of the Gods.mp3
03. Food of the Gods.mp3
04. Food of the Gods.mp3
05. Food of the Gods.mp3
06. Food of the Gods.mp3
07. Food of the Gods.mp3
08. Food of the Gods.mp3
09. Food of the Gods.mp3
10. Food of the Gods.mp3
11. Food of the Gods.mp3
12. Food of the Gods.mp3
12 renames from 12 entries (DRY RUN)

To actually perform these renames we run the command again with the -f flag. Note how the \1 group number expands to the first capturing group from SEARCH.

Mistakes Happen

What would happen if I made a mistake while 'optimising' my search pattern? Let's try it:

$ '\w+(\d\d)' '\1'
Aborting: Data-loss detected!
Both 'foodofgods_01_wells_64kb.mp3' and 'foodofgods_02_wells_64kb.mp3' 
rename to '64kb.mp3'

Oops. The capturing group matched the second set of two digits, as the \w+ pattern matched greedily. Even with the --force flag set this cantrip will refuse to perform the operation.


This script, as well as all of my other cantrips, can be downloaded from my public code repo.

Updated 24 Apr 2024, first published 13 Apr 2024