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!
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.
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
You can navigate your filesystem using the standard Unix commands
cd. Renaming is done inside a particular folder with the
rn all commands. To quit, enter
Rename (single file, change entire filename):
rn <current_filename.ext> <new_filename.ext>
$ Enter command: rn Airhorn.wav AIRHOOOORN.wav
Rename All (multiple files, replace LAST string match found):
rn all <string_input> <string_output>
$ Enter command: rn all Hihat HH
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.
q / quit
- 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
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
In the snippet above, we also see that
os.path.isdir() is used to throw an error if no directory is found.
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, or
os.path.isfile(path) - returns
trueif the supplied path is an existing file, or
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 and array and os.path.isfile(array): rename_whole_filename(array, array) 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 and a new filename at
os.path.isfile(array) 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.
Hilariously, the core functionality of this whole CLI boils down to one simple
Yep, that's it. Supply a string for
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
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
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...
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.
rn all, build in handling for spaces--currently, there is no working way to remove a substring without adding any characters!
rn all, build in an option to specify how many substring matches are replaced. (Originally, all matches were replaced--hence the switch to using
- 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
os.path modules below!