Studio Matrx Monthly · Volume 1 · Issue 3 · August 2026
Amogh N P
 In loving memory of Amogh N P — Architect · Designer · Visionary 
Automating Files and FoldersLesson 8.1
PSD for Architecture, Planning & Urban Design/Module 8 · Automation & the Everyday Toolkit

Lesson 8.1 · Automation & the Everyday Toolkit

Automating Files and Folders

os, pathlib, shutil and glob - the classic time-saver that turns an afternoon of clicking into a one-second script

13 min Interactive lessonFree · open lessonByAmogh N P· Architect & interior designer
The hook

Five hundred files, renamed and sorted in under a second - because you described the rule once and let the computer do the clicking.

Every design office runs on files: exported drawings, renders, PDFs, spec sheets, photographs - thousands of them, with inconsistent names, in the wrong folders, waiting to be tidied by hand. That tidying is pure drudgery, and it is exactly the kind of repetitive, rule-based work a script does for free.

This lesson is the classic first win of automation. With four pieces of Python's standard library - pathlib, os, shutil and glob - you will learn to walk a folder, rename in bulk, sort files into sub-folders by type, find files by pattern, and copy or move them safely. No installs, no libraries to add; every tool here ships with Python. Master this and you have automated the most universal chore in practice.

pathlib names, glob finds, shutil moves. Dictionary = the rule as data. Dry-run everything destructive.

A folder is just a list you can loop over

The mental shift that unlocks file automation is simple: a folder is a collection of paths, and a path is just text your code can inspect and act on. Once you see a directory as a list you can loop over, tidying it becomes the same input-process-output shape as any other script - read the files in, decide something about each, write a result out.

Modern Python gives you pathlib, an object-oriented way to handle paths that reads almost like English and works identically on Windows, macOS and Linux. A Path object knows its own pieces - name, stem (name without extension), suffix (the extension), parent folder - so you rarely fiddle with slashes by hand:

python
from pathlib import Path

folder = Path("exports")
for file in folder.iterdir():
    if file.is_file():
        print(file.name, file.suffix, file.stat().st_size)

folder.iterdir() yields every entry; file.is_file() skips sub-folders; file.suffix is .pdf or .jpg; file.stat().st_size is the size in bytes. That is enough to report on a folder - and reporting first, before you change anything, is a habit worth keeping. When you do want the path as text (some older functions expect a string), str(file) gives it back. Prefer pathlib for new code; you will still meet the older os.path style in examples online, and the two interoperate cleanly.

It is worth meeting that older os module too, because you will see it everywhere. os.listdir(folder) returns the filenames as plain strings, os.getcwd() reports the folder your script is running from, and os.path.join(a, b) builds a path with the correct separator. pathlib wraps all of this in one tidy object, but recognising the os names lets you read the vast body of code written before pathlib became the default. One small but important habit goes with this: always be explicit about which folder you are working in. A script that quietly assumes the current directory will do the wrong thing the moment a colleague runs it from somewhere else, so anchor your paths - Path(__file__).parent gives the folder the script itself lives in, a reliable starting point you can build from.

FIND -> FILTER -> ACTFINDglob("*.dwg")FILTERkeep newer thanlast issueACTcopy, rename,or move eachA pattern gathers paths, a test narrows them, one action runs on each. That is most file scripts.
Zoom
The find-filter-act pipeline. A glob pattern like *.dwg gathers matching paths, an optional test narrows them, and one action runs on each survivor. Reading a folder is just the input stage of the usual input-process-output shape.

A folder = a list of paths. Loop it, inspect .suffix / .stem, act. That is the whole game.

Batch renaming - the one-second afternoon

Renaming a set of exports to a consistent scheme is the canonical example, and pathlib makes it clean. The safe move is Path.rename(new_path), which renames within the same folder when you hand it a sibling path. Build the new name from the old one's parts so you never lose the extension:

python
from pathlib import Path

folder = Path("exports")
pdfs = sorted(folder.glob("*.pdf"))
for i, file in enumerate(pdfs, start=1):
    new_name = f"A-{i:03d}_{file.stem}{file.suffix}"
    file.rename(file.with_name(new_name))

Three things earn their keep here. folder.glob("*.pdf") gathers only the PDFs; sorted(...) makes the numbering stable and repeatable; and enumerate(..., start=1) gives you a running counter, formatted as {i:03d} so 7 becomes 007 and the files sort correctly in any file browser. file.with_name(new_name) returns a new Path in the same folder with a new filename - exactly what rename wants.

One hard-won rule: never let your output pattern collide with your inputs. If you rename 1.pdf to 2.pdf while 2.pdf still exists, you overwrite real work. Two safeguards: rename into a new folder rather than in place, or do a dry run first - loop through and print() the old-and-new pairs, read them with your own eyes, and only then swap the print for the real rename. A dry run costs ten seconds and has saved many a project.

It is worth understanding why sorted() matters beyond neatness. File systems do not guarantee any particular order from iterdir() or glob(), so without sorting your A-001 prefix might attach to a different file each time you run - a subtle, maddening bug. Sorting makes the operation deterministic: the same input folder always yields the same numbering, exactly what you want for something you will re-run. If the names need to sort a particular way - by date, or by an embedded sheet number - pass a key function, for example sorted(pdfs, key=lambda p: p.stat().st_mtime) to number them oldest-first.

Dry-run first: print old -> new, eyeball it, THEN rename. Zero-pad numbers with {i:03d}.

Sorting a chaotic folder by type

The second everyday win is sorting a mixed dumping-ground - a downloads folder, a shared drive, an export dump - into tidy sub-folders by file type. The logic is: for each file, look at its extension, map that to a destination folder, make the folder if needed, and move the file there. shutil handles the actual moving and copying (pathlib deliberately does not), so the two libraries pair up:

python
import shutil
from pathlib import Path

folder = Path("downloads")
buckets = {
    ".pdf": "pdf", ".jpg": "images", ".png": "images",
    ".xlsx": "sheets", ".csv": "sheets", ".dwg": "cad",
}
for file in folder.iterdir():
    if not file.is_file():
        continue
    target = buckets.get(file.suffix.lower(), "other")
    dest = folder / target
    dest.mkdir(exist_ok=True)
    shutil.move(str(file), str(dest / file.name))

Read it slowly. The buckets dictionary is your rule, expressed as data - to support a new file type you add one line, you do not touch the logic. file.suffix.lower() normalises .JPG and .jpg to the same key. buckets.get(key, "other") looks up the destination and falls back to an "other" folder for anything unexpected, so nothing is ever lost. dest.mkdir(exist_ok=True) creates the sub-folder and quietly does nothing if it already exists. Finally shutil.move relocates the file. Swap shutil.move for shutil.copy2 and you get the same sort while preserving the originals - copy2 also carries over timestamps, which matters when you sort by date later.

A subtlety worth flagging: shutil.move across different drives or partitions is really a copy-then-delete under the hood, so it can be slower and briefly needs room for both copies - fine for a downloads folder, worth knowing for very large media libraries. Within a single drive it is near-instant. And because the destination sub-folders are created on demand with mkdir(exist_ok=True), the script is safe to run more than once: a second run simply finds the folders already there and sorts whatever new files have arrived since, so you can point it at the same growing folder every week.

SORT A FOLDER BY RULEexports/plan.pdfview.jpgboq.xlsxdetail.pdfrender.pnglook atthe extensionpdf/images/sheets/Inspect each file, decide by a rule, move it. Five files or five thousand - the same loop.
Zoom
Sorting a messy folder by rule: read every file, look at its extension, and route each one to the right sub-folder. The same shape - inspect, decide, move - underlies almost every file-automation script.

Finding files by pattern - glob and rglob

Often you do not want every file, only the ones matching a pattern - all DWGs, everything with _final in the name, all images issued this week. glob is pattern-matching for filenames, using two wildcards: * matches any run of characters, ? matches a single character. folder.glob("*.dwg") finds DWGs in one folder; folder.rglob("*.dwg") (recursive glob) walks every sub-folder too - invaluable across a nested project tree:

python
from pathlib import Path

project = Path("project_A")
finals = [p for p in project.rglob("*_final*.pdf")]
print(f"Found {len(finals)} final PDFs")

for p in finals:
    print(p.relative_to(project))

The list comprehension [p for p in project.rglob("*_final*.pdf")] collects the matches into a list so you can count them, sort them, or feed them to the next step. p.relative_to(project) prints a short path relative to the project root instead of the full absolute path. From here you compose: find with glob, filter further with an if (for example if p.stat().st_mtime > cutoff to keep only recently modified files), and act with shutil. That find-filter-act pipeline - the second figure - is the backbone of file automation, and once it is muscle memory you will reach for it constantly. A closing caution worth stating plainly: file operations are destructive. rename, move and especially deletion do not ask twice. Test on a copy, keep a backup, and dry-run anything that renames or moves in bulk until you trust it.

From a one-off to a tool you keep

A script you write, run once and lose is perfectly fine - but the chores in this lesson recur every week, so the real leverage comes from turning them into a small tool you keep. The move is to wrap the logic in a function with the folder as a parameter, so the same code serves any project:

python
from pathlib import Path
import shutil

def sort_folder(folder, buckets, dry_run=True):
    folder = Path(folder)
    for file in folder.iterdir():
        if not file.is_file():
            continue
        target = buckets.get(file.suffix.lower(), "other")
        dest = folder / target
        if dry_run:
            print(f"would move {file.name} -> {target}/")
        else:
            dest.mkdir(exist_ok=True)
            shutil.move(str(file), str(dest / file.name))

Notice the dry_run=True default: the function is safe by design - it only reports until you deliberately call it with dry_run=False. That single parameter bakes the dry-run habit into the tool itself, so the cautious path is the easy one. Save this in a file you reuse across projects and you have started building a personal toolkit, which is exactly how working scripters accumulate leverage over a career.

One more everyday filter is by time. Every file carries a last-modified timestamp, file.stat().st_mtime, as a number of seconds; compare it to a cutoff to act only on what changed since the last issue:

python
import time
cutoff = time.time() - 7 * 24 * 3600   # seven days ago
recent = [p for p in folder.glob("*.pdf")
          if p.stat().st_mtime > cutoff]

Finally, be honest about the economics. Automation is leverage, not a reflex. A task you do once, on five files, is not worth a script - the ten minutes spent scripting a genuinely one-off job are ten minutes lost, and this course would rather you knew that than automated for its own sake. The tasks worth the effort are the recurring ones: the sort you run every issue, the rename on every export, the audit before every submission. When you meet one of those, promote your throwaway script into a kept function, and it pays back quietly for the rest of the project's life.

Tools & terms in this lesson

pathlib.Path

Object-oriented file paths

The modern default: .name, .stem, .suffix, .parent, glob() and rglob(). Cross-platform and readable; prefer it over raw os.path strings.

shutil

High-level file operations

move(), copy2(), rmtree() and more. pathlib deliberately does not move or copy - shutil is its partner for that.

glob / rglob

Match filenames by pattern

* matches any characters, ? one character. rglob recurses into sub-folders. The find stage of find-filter-act.

os module

The older path/OS interface

os.listdir, os.rename, os.path.join. Still everywhere in examples online; interoperates with pathlib. Learn to read it, prefer pathlib to write it.

Hands-on workshop

Workshop — the sort-and-rename tidier

Build a small script that tidies a real folder: it renames files to a consistent scheme and sorts them into sub-folders by type. You will practise the whole find-filter-act loop on files you can safely experiment with.

Python 3 (standard library only - no installs). A code editor or Jupyter. A disposable copy of a real folder to practise on.

Given & goal
Goal: rename + sort a folder by type, safely
Inputs: a copy of a messy folder (downloads or exports)
Time: ~40 minutes
  1. 1Copy a real messy folder to a scratch location so the originals are safe. Point your script at the copy only. Confirm the path with Path("scratch").exists().
  2. 2Write a dry run: loop the folder with iterdir(), and for each file print(file.name, file.suffix). Run it and read the output - you now know exactly what you are working with.
  3. 3Add a buckets dictionary mapping extensions to folder names. For each file, compute its target with buckets.get(file.suffix.lower(), "other") and print the intended move (still no real moving yet).
  4. 4When the printed plan looks right, replace the print with dest.mkdir(exist_ok=True) then shutil.move(...). Run it and inspect the tidied folder.
  5. 5Extend it: before moving, rename each file to include its bucket and a zero-padded index (f"{target}-{i:03d}{file.suffix}"). Re-run on a fresh copy and confirm nothing collides or is lost.

You’ll walk away with
A working script that takes a messy folder and produces a tidy one - files renamed to a consistent, zero-padded scheme and sorted into type sub-folders - developed via a dry run first, with the originals untouched.

The worked example

Three altitudes on the same idea

Read the band that fits you — or all three.

For the architectAutomate busywork & build custom tools

Drawing issue is a renaming-and-sorting problem in disguise. Every issue, you export a set, rename it to the office standard, sort by discipline, and file it by revision - by hand, every time. A twenty-line script encodes your naming convention once and runs it on every future issue in a second, with none of the transposition errors that creep in at 6pm. Point rglob at a project tree and you can also audit it: list every file missing a revision suffix, or every PDF older than the current issue.

For the interior designerScripts for data, schedules & layouts

Your bottleneck is usually media, not geometry. Hundreds of product photos, moodboard images, finish samples and supplier PDFs arrive with useless names like IMG_8842.jpg and pile up in one folder. A sorting script routes them into images/, pdf/ and sheets/ by type, and a renaming script can stamp them with the room or the supplier so they are findable months later. This is the single most reusable script in an interiors workflow - write it once, run it on every project.

For the studentA hireable computational skill

Your assignment and portfolio folders are the perfect practice ground. Semesters of downloads, references, drafts and final submissions accumulate into chaos. Automating the cleanup teaches you pathlib, glob and shutil on files you actually care about, and the same skills reappear the moment you script a render farm, a dataset, or a batch export in practice. Employers reading your CV notice a candidate who automates their own workflow - it signals exactly the computational literacy that studios now want.

Misconception check

File automation is risky - one bad script and I will wipe out my project files, so it is safer to do it by hand.

The risk is real but it is entirely controllable, and doing it by hand carries its own quieter risk of human error. The disciplined habits are simple: work on a copy of the folder while developing; do a dry run that only prints the old-and-new paths so you can read them before anything changes; and prefer moving files into a new output folder over renaming in place. With those three habits, bulk file operations are far safer than hand-editing five hundred files, where a slip goes unnoticed. Automation does not remove your judgement - it just applies your checked-and-approved rule uniformly. Treat destructive operations with respect, test small, and the leverage is enormous with negligible danger.
Try it

Do it yourself

Reason about the code before running it.

  1. 1What does file.suffix return for a path named plan_final.PDF, and why call .lower() on it before matching?
  2. 2Why is a dry run - printing old and new paths before renaming - worth the extra ten seconds?
  3. 3What is the difference between folder.glob("*.dwg") and folder.rglob("*.dwg")?
  4. 4Which library actually moves a file - pathlib or shutil - and why does it matter?
  5. 5How would you change a sort script to keep the originals instead of moving them?
Take this with you

The one line to carry out

Treat a folder as a list of paths you can loop over: find with glob, decide with a rule expressed as data, and act with pathlib and shutil - always after a dry run. The most universal chore in practice becomes a one-second script, safely.
Take it further
References & further reading

Peer-reviewed journals & authoritative standards

  1. 01os - Miscellaneous operating system interfacesPython documentation, 2026.
  2. 02The Python Standard LibraryPython documentation, 2026.
  3. 03Python (programming language)Wikipedia, 2026.
  4. 04Scripting languageWikipedia, 2026.
Related lessons
Recap
Files are the universal drudgery of design offices, and Python's standard library automates them without a single install. pathlib reads and names paths cleanly; glob and rglob find files by pattern; shutil moves and copies. Batch renaming, sorting by type, and pattern-finding all follow the same find-filter-act loop. Because these operations are destructive, dry-run and work on copies until you trust the script.
Carry forward →

Files are the container; often the payload is media. Next we open those files and transform their contents in bulk - resizing, watermarking and converting whole folders of images, and merging, splitting and extracting PDFs.

A

The author

Amogh N P

Architect, interior designer, and creative polymath. Studio Matrx began in his notebooks — his vision of design made honest, useful, and open to everyone. Its Academy is written and taught in his memory, and free, forever.

More about Amogh →