October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk9 min

7 Python Scripts That Kill Repetitive Busywork (Standard Library Only)

Seven small standard-library Python scripts for renaming, sorting, backing up, zipping, CSV cleanup, reporting, and running external tools, each with a safe preview mode.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Seven chores are worth automating with nothing but the Python standard library: batch renaming, sorting a folder, dated backups, ZIP archiving, CSV cleanup, repeatable reports, and calling a trusted external tool. Each script below is short and bounded, and each one that changes files previews first. No pip installs are needed.

One caveat up front: no source reviewed for this article measured how much time scripts like these save, so none is promised. The code follows behavior documented in Python’s tutorial and library reference, but it is example code, not a tested product. Run every script on a copy of your data before trusting it.

Ground rules that apply to all seven

  • Preview by default. Scripts that rename, move, or write files print what they would do and only act when you pass --apply.
  • Explicit paths. Folders come from command-line arguments, not from “whatever directory I happen to be in”.
  • Never overwrite silently. Each script checks for name collisions and skips instead of replacing.
  • Keep originals until you have checked the output. Cleanup and deletion stay manual.

Requires Python 3.8 or newer for the code shown. Save each script as its own file and run it with python script_name.py --help to see its options.

1. Batch rename files

Use it when a folder holds files such as IMG_4471.jpg and you want trip-001.jpg, trip-002.jpg, and so on. pathlib handles the paths; the rename itself is Path.rename.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import argparse
from pathlib import Path

parser = argparse.ArgumentParser(description="Rename .jpg files to PREFIX001.jpg, PREFIX002.jpg ...")
parser.add_argument("folder", type=Path)
parser.add_argument("--prefix", default="trip-")
parser.add_argument("--apply", action="store_true", help="actually rename (default is preview)")
args = parser.parse_args()

if not args.folder.is_dir():
    raise SystemExit(f"Not a folder: {args.folder}")

files = sorted(args.folder.glob("*.jpg"))
for number, old in enumerate(files, start=1):
    new = old.with_name(f"{args.prefix}{number:03d}{old.suffix}")
    if new == old:
        continue
    if new.exists():
        print(f"SKIP (target exists): {old.name} -> {new.name}")
        continue
    print(f"{old.name} -> {new.name}")
    if args.apply:
        old.rename(new)

Expected result: a preview list of old and new names. Re-run with --apply once it looks right. Note that glob("*.jpg") is case-sensitive on Linux, so .JPG files will not match there.

2. Sort a downloads or project folder

Use it when a folder has become a dumping ground. Match by extension, keep the category list small, and move with shutil.move.

import argparse
import shutil
from pathlib import Path

CATEGORIES = {
    "Images": {".jpg", ".jpeg", ".png", ".gif"},
    "Documents": {".pdf", ".docx", ".txt", ".xlsx"},
    "Archives": {".zip", ".tar", ".gz"},
}

parser = argparse.ArgumentParser(description="Move files into category subfolders.")
parser.add_argument("folder", type=Path)
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()

if not args.folder.is_dir():
    raise SystemExit(f"Not a folder: {args.folder}")

for item in sorted(args.folder.iterdir()):
    if not item.is_file():
        continue
    for category, extensions in CATEGORIES.items():
        if item.suffix.lower() in extensions:
            target_dir = args.folder / category
            target = target_dir / item.name
            if target.exists():
                print(f"SKIP (exists): {target}")
            else:
                print(f"{item.name} -> {category}/")
                if args.apply:
                    target_dir.mkdir(exist_ok=True)
                    shutil.move(str(item), str(target))
            break

Files that match no category stay where they are, which is the safe default. Because only top-level files are examined, existing subfolders are not touched.

3. Make a dated backup copy

Use it when you are about to edit or clean a folder and want a snapshot first. shutil.copytree copies a directory tree; by default it uses copy2, which tries to keep timestamps and permission bits.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import argparse
import shutil
from datetime import datetime
from pathlib import Path

parser = argparse.ArgumentParser(description="Copy a folder to a timestamped backup.")
parser.add_argument("source", type=Path)
parser.add_argument("backup_root", type=Path)
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()

if not args.source.is_dir():
    raise SystemExit(f"Source not found: {args.source}")

stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
destination = args.backup_root / f"{args.source.name}-{stamp}"
print(f"{args.source} -> {destination}")

if args.apply:
    args.backup_root.mkdir(parents=True, exist_ok=True)
    shutil.copytree(args.source, destination)
    print("Done.")

Limit to know about: Python’s documentation notes that its copy functions cannot preserve every kind of metadata on every platform (for example, some operating-system-specific attributes). Treat this as a file-level safety copy, not a full system clone. Keep the backup folder outside the source folder, or the copy will try to include itself on later runs.

4. Archive a finished project folder

Use it when a project is closed and you want one tidy ZIP. The zipfile module writes the archive; this script then verifies it before you decide to delete anything.

import argparse
import zipfile
from pathlib import Path

parser = argparse.ArgumentParser(description="Zip a folder and verify the archive.")
parser.add_argument("folder", type=Path)
parser.add_argument("output", type=Path, help="e.g. archive/project-2026.zip")
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()

if not args.folder.is_dir():
    raise SystemExit(f"Not a folder: {args.folder}")
if args.output.exists():
    raise SystemExit(f"Refusing to overwrite: {args.output}")

files = [p for p in sorted(args.folder.rglob("*")) if p.is_file()]
print(f"{len(files)} files would be added to {args.output}")

if args.apply:
    args.output.parent.mkdir(parents=True, exist_ok=True)
    with zipfile.ZipFile(args.output, "w", compression=zipfile.ZIP_DEFLATED) as zf:
        for path in files:
            zf.write(path, arcname=path.relative_to(args.folder.parent))
    with zipfile.ZipFile(args.output) as zf:
        bad = zf.testzip()
        if bad or len(zf.namelist()) != len(files):
            raise SystemExit("Verification failed - keep the originals.")
    print("Archive verified. The source folder was not deleted.")

Write the ZIP somewhere outside the folder being archived. The script deliberately never deletes the source; do that by hand after opening the archive and spot-checking a few files. Empty directories are not stored because only files are added.

5. Clean or combine CSV exports

Use it when an export has stray whitespace, inconsistent casing, or duplicate rows. The csv module is enough for row-level cleanup, so pandas is unnecessary here. This example assumes columns named name and email; change them to match your file.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import argparse
import csv
from pathlib import Path

parser = argparse.ArgumentParser(description="Normalize and de-duplicate a CSV by email.")
parser.add_argument("input", type=Path, nargs="+", help="one or more CSV files")
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()

if args.output.exists():
    raise SystemExit(f"Refusing to overwrite: {args.output}")

seen = set()
kept = []
dropped = 0
for path in args.input:
    with path.open(newline="", encoding="utf-8-sig") as f:
        for row in csv.DictReader(f):
            row["name"] = " ".join(row["name"].split()).title()
            row["email"] = row["email"].strip().lower()
            if not row["email"] or row["email"] in seen:
                dropped += 1
                continue
            seen.add(row["email"])
            kept.append(row)

with args.output.open("w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "email"], extrasaction="ignore")
    writer.writeheader()
    writer.writerows(kept)

print(f"Kept {len(kept)} rows, dropped {dropped} blank or duplicate rows.")

The duplicate rule is stated, not guessed: the first row with a given lower-cased email wins. The output is a new file, so the originals are untouched, and the newline="" argument is what the csv documentation asks for when opening files. Two cautions: .title() mangles names like “McDonald”, so drop that line if casing matters, and extrasaction="ignore" discards any other columns, so list every column you want to keep in fieldnames.

6. Generate a repeatable command-line report

Use it when you re-run the same summary every week with a different date range. argparse turns it into a tool with named options and automatic --help. This example totals an amount column by category for rows whose date (YYYY-MM-DD) falls in range.

import argparse
import csv
from collections import defaultdict
from datetime import date
from decimal import Decimal
from pathlib import Path

parser = argparse.ArgumentParser(description="Total amounts by category for a date range.")
parser.add_argument("input", type=Path)
parser.add_argument("--start", type=date.fromisoformat, required=True)
parser.add_argument("--end", type=date.fromisoformat, required=True)
parser.add_argument("--output", type=Path, help="write report here instead of printing")
args = parser.parse_args()

totals = defaultdict(Decimal)
with args.input.open(newline="", encoding="utf-8-sig") as f:
    for row in csv.DictReader(f):
        day = date.fromisoformat(row["date"])
        if args.start <= day <= args.end:
            totals[row["category"]] += Decimal(row["amount"])

lines = [f"{cat}: {total:.2f}" for cat, total in sorted(totals.items())]
report = "n".join(lines) or "No rows in range."

if args.output:
    if args.output.exists():
        raise SystemExit(f"Refusing to overwrite: {args.output}")
    args.output.write_text(report + "n", encoding="utf-8")
else:
    print(report)

Run it like this: python report.py sales.csv --start 2026-09-01 --end 2026-09-30. The input file is only read, never modified. A malformed date or amount raises an error naming the bad value, which is preferable to silently skipping rows.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

7. Run a trusted external program and capture the result

Use it when an installed tool already does a step you need, such as Git, a converter, or a backup utility, and you want its output inside a script. Use subprocess.run with an argument list, not a single command string.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import subprocess
import sys

repo = sys.argv[1]  # e.g. /home/me/projects/site

try:
    result = subprocess.run(
        ["git", "-C", repo, "status", "--short"],
        capture_output=True,
        text=True,
        timeout=30,
        check=True,
    )
except FileNotFoundError:
    raise SystemExit("git is not installed or not on PATH.")
except subprocess.TimeoutExpired:
    raise SystemExit("git took longer than 30 seconds.")
except subprocess.CalledProcessError as err:
    raise SystemExit(f"git failed ({err.returncode}): {err.stderr.strip()}")

print(result.stdout or "Working tree clean.")

The argument list means the path in repo is passed as a single argument and is not parsed by a shell, so spaces and special characters do not change the command’s meaning. Avoid shell=True unless you have a concrete need, and never combine it with text you did not write; Python’s subprocess documentation has a dedicated security section on this. Only run programs you trust, since the script inherits whatever that program does.

Choosing which to write first

Script Changes your files? Main risk Safeguard in the example
1. Batch rename Yes (renames) Name collisions, hard to undo Preview, skip if target exists
2. Sort folder Yes (moves) Misfiled items, collisions Preview, skip if target exists
3. Dated backup No (adds a copy) Incomplete metadata, disk space Timestamped destination, preview
4. ZIP archive No (adds an archive) Deleting sources too early Verification, never deletes
5. CSV cleanup No (new file) Wrong duplicate rule, dropped columns Writes a new file, reports counts
6. Report No (read-only) Bad input data Strict parsing, no overwrite
7. External program Depends on the tool Shell injection, hangs Argument list, timeout, error handling

Start with 3 or 6: they cannot damage anything, so they are the safest way to get comfortable. Make 3 a habit before you run 1 or 2, because rename and move scripts are the ones that can scramble a folder.

Cross-platform notes

  • Paths: pathlib handles / versus for you; avoid building paths with string concatenation.
  • Case sensitivity: Linux file systems are usually case-sensitive; Windows and default macOS volumes usually are not. Extension matching in the examples lower-cases suffixes for that reason, except the glob pattern in script 1.
  • Running on a schedule: once a script is trustworthy, you can run it from your system’s scheduler. Do that only after you have used the preview mode on real data several times.

Where to go next

The argparse, shutil, zipfile, csv, and subprocess pages in the official Python documentation, and the standard-library tour in the official tutorial, cover the options these examples leave out. Automate the Boring Stuff with Python is a well-known longer learning path for the same kind of task, though this article did not verify the current edition or availability.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.