LinearAndLoom Icons

Clean Up File Names in Bulk (Free Python Script)

Free Python script that renames every file in a folder to clean, lowercase, web-safe names: no spaces, accents or symbols.

Download clean-filenames-snake-case.pyPython 3 · 93 lines · 3 KB · free

File names with spaces, capitals, accents and symbols cause trouble: broken links on websites, upload errors on marketplaces and messy URLs. This script renames every file in a folder to a clean, lowercase name in one go.

What it does

It works on the files directly inside the folder you give it, not in subfolders.

How to use it

  1. Run the script (see below).
  2. When it asks Enter folder path:, paste the path of your folder, or drag the folder into the terminal window, and press Enter.
  3. The script prints every change, for example Renamed: My Photo.JPG -> my_photo.jpg.

Renaming cannot be undone with Ctrl+Z. Run the script on a copy of the folder the first time, until you trust the result.

How to run a Python script

  1. Install Python 3 from python.org if you do not have it. It is free. On Windows, tick Add Python to PATH in the installer.
  2. Download the script with the button on this page and save it somewhere easy, such as your Desktop.
  3. Open a terminal. On Windows, press the Windows key, type cmd and press Enter. On Mac, open Terminal from Applications > Utilities.
  4. Type python followed by a space (on Mac, python3 and a space), drag the script file into the terminal window and press Enter.

Why clean file names matter

Questions

Can I use hyphens instead of underscores?

Yes. Run this script first, then run the find and replace script on the same folder to swap _ for -.

Does it rename files in subfolders?

No, only the files directly in the folder you enter. Run it once per folder.

What happens to names in other alphabets?

Letters with accents are converted to plain letters. Characters with no plain equivalent, such as Arabic or Chinese, are removed. A file whose whole name is removed is called file.

The code

This is the complete script. Nothing else is downloaded or installed.

"""Clean file names (snake_case)

Renames every file in one folder to a clean, lowercase, web-safe name:
"My Photo (Final) #2.JPG" becomes "my_photo_final_2.jpg".

Free script from LinearAndLoom Icons: https://linearandloomicons.netlify.app/scripts/
Provided as is. Renaming and zipping cannot be undone, so try it on a copy of your folder first.
"""
import re
import unicodedata
from pathlib import Path


def to_snake_case_filename(filename: str, max_length: int = 180) -> str:
    """
    Convert filename to clean SEO-friendly snake_case.
    Preserves extension and removes invalid characters.
    """
    path = Path(filename)
    stem = path.stem
    suffix = path.suffix.lower()

    # Normalize unicode → ASCII
    stem = unicodedata.normalize("NFKD", stem)
    stem = stem.encode("ascii", "ignore").decode("ascii")

    # Lowercase for snake_case
    stem = stem.lower()

    # Remove invalid filename chars (Windows + cross-platform safe)
    stem = re.sub(r'[<>:"/\\|?*\x00-\x1F]', "", stem)

    # Replace any non-alphanumeric sequence with underscore
    stem = re.sub(r"[^a-z0-9]+", "_", stem)

    # Remove repeated underscores
    stem = re.sub(r"_+", "_", stem)

    # Strip leading/trailing underscores
    stem = stem.strip("_")

    # Prevent empty names
    if not stem:
        stem = "file"

    # Trim total length safely
    max_stem_len = max_length - len(suffix)
    stem = stem[:max_stem_len].rstrip("_")

    return stem + suffix


def normalize_folder_filenames(folder_path: str):
    folder = Path(folder_path)

    if not folder.exists() or not folder.is_dir():
        print("Invalid folder path.")
        return

    used_names = set()
    this_script = Path(__file__).resolve()

    # List the files first, so files renamed along the way are not picked up twice
    for file in sorted(f for f in folder.iterdir() if f.is_file()):
        # Leave hidden system files (.DS_Store, .gitignore) and this script alone
        if file.name.startswith(".") or file.resolve() == this_script:
            continue

        new_name = to_snake_case_filename(file.name)
        new_path = folder / new_name

        # Handle duplicates
        base_stem = Path(new_name).stem
        suffix = Path(new_name).suffix
        counter = 1

        # samefile() keeps "Photo.JPG" -> "photo.jpg" working on Windows and macOS,
        # where both names point to the same file
        while new_name in used_names or (new_path.exists() and not new_path.samefile(file)):
            new_name = f"{base_stem}_{counter}{suffix}"
            new_path = folder / new_name
            counter += 1

        used_names.add(new_name)

        if file.name != new_name:
            file.rename(new_path)
            print(f"Renamed: {file.name} -> {new_name}")


if __name__ == "__main__":
    folder_path = input("Enter folder path: ").strip().strip('"').strip("'")
    normalize_folder_filenames(folder_path)

Download clean-filenames-snake-case.pyPython 3 · 93 lines · 3 KB · free

These scripts are free. If one saved you time, you can say thanks by buying a pack from the LinearAndLoom Etsy shop.

More scripts