Github repo: https://github.com/isalevine/file-renamer
One of my hobbies is making electronic music, and thanks to resources like samplesfrommars.com, I have tons and tons of audio files to manage. One drawback of the my main drum machine is that it limits readable filenames--anything after a certain number of characters is cut off, and any name-collisions will point to the first file with that name.
A lot of my music sample library has folders full of long, repetitive filenames, like this:
I got really tired of renaming them one-by-one, so I wrote my first Python script, file-renamer, as a CLI to do mass-renaming!
file-renamer Overview
Basically, I wanted a way to change or remove specific strings from multiple filenames at once. As a CLI, file-renamer also provides a way to navigate a filesystem to modify files in different folders quickly and easily from the command line.
Setup
After cloning the repo to your computer, you can run file-renamer with $ python3 script.py in the repo's directory.
The only configuration you will need to do is setting a default path. See script.py line 37 (as of this writing) for the code to change:
# script.py
path = os.path.realpath('./drum-samples') # set default path here
Use
You can navigate your filesystem using the standard Unix commands pwd, ls, and cd. Renaming is done inside a particular folder with the rn or rn all commands. To quit, enter q or quit.
Change Directory:
cd
List Files:
ls
Print Directory:
pwd
Rename (single file, change entire filename):
rn <current_filename.ext> <new_filename.ext>
Ex.
$ Enter command: rn Airhorn.wav AIRHOOOORN.wav
Rename All (multiple files, replace LAST string match found):
rn all <string_input> <string_output>
Ex.
$ Enter command: rn all Hihat HH
Note: Currently, rn all will replace the LAST matching instance of <string_input> encountered in the filename (i.e. first match encountered when reading right-to-left). See str.rpartition() in the Python docs for more information.
Exit Program:
q / quit
  
  
  Python's pathlib, os, and os.path modules
The functionality of this script is powered by Python's  pathlib, os, and os.path modules. Here's how they're used:
Navigating filesystem:
- os.path.realpath(path) - returns a string with the full filepath for a supplied file or directory
 - os.path.join(path1, path2, ...) - returns a concatenated string from supplied paths (with included separators)
 - Path.parent - returns a string of the path's parent directory
 
All of these methods return strings which can be passed to pathlib.Path(str) to create a Path object, which is similar to a string but has different functionality:
- 
pathlib.Path(str) - creates a 
Pathobject out of a supplied string 
In the file-renamer code, here's how they are implemented:
# script.py
import pathlib
import os
path = os.path.realpath('./drum-samples')   # set default path here
current_directory = pathlib.Path(path)
...
# inside main loop, after getting user_input
        if user_input[0:2] == "cd":
            temp_directory = current_directory
            if user_input[3:5] == "..":
                new_path = current_directory.parent
                current_directory = pathlib.Path(new_path)
            else:
                new_path = os.path.join(current_directory, user_input[3:])
                current_directory = pathlib.Path(new_path)
...
        if not os.path.isdir(current_directory):
            print("Not a valid directory!")
            current_directory = temp_directory
Here, when user_input is cd .. , a new_path string is created from current_directory.parent, and is turned back into a Path object with current_directory = pathlib.Path(new_path).
Otherwise, when user input is cd followed by something else, new_path is a string created by using os.path.join to add the contents of user_input onto the end of current_directory.
Validate file and directory names:
In the snippet above, we also see that os.path.isdir() is used to throw an error if no directory is found. 
The os.path module provides a number of useful validation methods, including two which are used in this script:
- 
os.path.isdir(path) - returns 
trueif the supplied path is an existing directory, orfalseif not - 
os.path.isfile(path) - returns 
trueif the supplied path is an existing file, orfalseif not 
In addition to the above snippet, we see os.path.isfile() in action here:
# script.py
# Here, array comes from using .split() on user_input
    if array[1] and array[2] and os.path.isfile(array[1]):
        rename_whole_filename(array[1], array[2])
    else:
        print("Rename aborted! (Probably because the original filename wasn't found.)")
After validating that the user_input variable, now split into array, contains an existing filename at array[1] and a new filename at array[2], os.path.isfile(array[1]) allows us to confirm that the existing filename actually exists. Otherwise, it will return false, which we handle with an else: error message.
Same thing happens with os.path.isdir(current_directory) above--it confirms that current_directory is an existing directory.
Rename files:
Hilariously, the core functionality of this whole CLI boils down to one simple os method:
Yep, that's it. Supply a string for src and dst, and os.rename() will take care of changing the filename.
Here's how it's used in the code:
# script.py
def rename_partial_filename(filename, input, output):
    src = str(filename)
    head, sep, tail = src.rpartition(input)
    dst = head + output + tail
    os.rename(src, dst)
    return dst
Here, src.rpartition(input) allows us to search the filename-string src from right-to-left, searching for a match for the string input. If found, that one instance is replaced with the given string output, and reconcatenated as the string dst. Calling os.rename(src, dst) will change the filename in your system.
Note: This method currently encounters errors when a file does NOT contain the given input! Instead, it will continue searching with .rpartition() until it finds a match in its parent directories, potentially causing directory errors! You've been warned...
That's it! Now you're ready to mass-rename your files! :)
Interested in contributing?
Once again, here's the link to the GitHub repo: https://github.com/isalevine/file-renamer
Please feel free to fork/clone/hack apart as you wish! If you do, I'd love to hear how you're using the script, whether it's for music sample libraries or something else entirely.
If you'd like to tackle some specific issues with the current code, here are a few on my list:
- In 
rnandrn all, build in handling for spaces--currently, there is no working way to remove a substring without adding any characters! - In 
rn all, build in an option to specify how many substring matches are replaced. (Originally, all matches were replaced--hence the switch to using.rpartition()...) - Add output logs for filename changes--currently, text is output to the console, but could easily be captured in a log file.
 
Thanks for reading! Please feel free to share any tips or advice for working with Python's pathlib, os, and os.path modules below!


    
Top comments (0)