I love writing scripts to solve small problems
One of the reasons I like programming so much is that it allows me to automate small and annoying things that would otherwise require bunch of manual work.
Yesterday, I downloaded a set of files that came in a following directory structure inside a zip file:
- Main Folder
- Theme A (1)
- FileA.pdf
- FileA.txt
- FileA.jpg
- Theme B (2)
- FileB.pdf
- FileB.txt
- FileB.jpg
- Theme C (3)
...
For my use case though, I was only interested in the pdf files and wanted to record the order of those files that was written in parentheses in the folder. I could have manually moved them all to a new folder in Finder but since there were a few dozen of them, I opened my editor and started writing Python.
import os
import re
import shutil
NUMBER_PATTERN = re.compile(r'\((\d+)\)')
for directory, _, files in os.walk('.'):
if directory == './Output':
continue
for filename in files:
if not filename.endswith('.pdf'):
continue
episode_number = NUMBER_PATTERN.findall(directory)[0]
path = os.path.join(directory, filename)
new_filename = f'{episode_number:0>2} - {filename}'
new_path = os.path.join('Output', new_filename)
print(f'Copying {path} to {new_path}')
shutil.copyfile(path, new_path)
It's a single-run script that relies on a very specific naming and file structure as well as the existence of Output folder. So if something's out of order, it just breaks.
That means it's not very maintainable and it probably isn't the best nor most pythonic code I could write. But since it's a script meant to run once in this very particular situation, I can recover from error situations manually.
And that's the beauty of it. It doesn't have to be good code, it just has to work once. It saves me lots of annoying manual copying and renaming files.
As opposed to the quest of writing good, maintainable and error-resistant code at work for production, these scripts allow me to get small wins by just scraping some code together.
edit I want to highlight this beautiful bash script that @teroyks created in the comments of this post in DEV:
find . -iname "*.pdf" | while read F; do FILE=$(basename "$F"); NR=$(printf "%02d" "$(echo "$F" | sed "s/.*(\(.*\)).*/\1/")"); cp -v "$F" "./Output/$NR - $FILE"; done
edit2 @teroyks also provided us an example in fish shell:
for f in (find . -iname "*.pdf")
set file (basename $f)
set number (string match -r "\((.*)\)" $f)[2]
set number (printf "%02d" $number)
cp -v $f "./Output/$number - $file"
end