Trimming Down Long Directory and File Names using Python

This Python script takes a directory path and then proceeds to scan every file and sub-directory within, looking for any filenames or directory names that exceed a specified length. Once found, the script truncates these names to fit within the desired length and appends an ellipsis (e.g., ...) to indicate the truncation. The beauty of this script lies in its configurability and the safety features embedded within it.

Note: Using this script will lose information (because the new filenames will be shorter and any important information in the rest of the filename will be lost forever). Additionally, it might lose information in other ways. Even though we have tested it carefully, it might still destroy your data in unexpected ways. Use a

How to use

The script provides the following command line options:

usage: FixLongFilenames.py [-h] [-n LENGTH] [--ellipsis ELLIPSIS] [--dry] directory

Shorten long filenames and directory names.

positional arguments:
  directory             The directory to process.

options:
  -h, --help            show this help message and exit
  -n LENGTH, --length LENGTH
                        The maximum allowable length for directory or file names.
  --ellipsis ELLIPSIS   The ellipsis to use when shortening.
  --dry                 Dry run mode, only log what would be renamed without actual renaming.

Source code

#!/usr/bin/env python3
import os
import argparse

def shorten_path(path, max_length, ellipsis, dry_run):
    if os.path.isdir(path):
        base_name = os.path.basename(path)
        if len(base_name) > max_length:
            new_name = base_name[:max_length] + ellipsis
            new_path = os.path.join(os.path.dirname(path), new_name)
            if not os.path.exists(new_path):
                if dry_run:
                    print(f"[DRY RUN] Directory would be renamed: {path} -> {new_name}")
                else:
                    os.rename(path, new_path)
                    print(f"Renamed directory: {path} -> {new_name}")
                return new_path
    else:
        base_name, ext = os.path.splitext(os.path.basename(path))
        if len(base_name) > max_length:
            new_name = base_name[:max_length] + ellipsis + ext
            new_path = os.path.join(os.path.dirname(path), new_name)
            if not os.path.exists(new_path):
                if dry_run:
                    print(f"[DRY RUN] File would be renamed: {path} -> {new_name}")
                else:
                    os.rename(path, new_path)
                    print(f"Renamed file: {path} -> {new_name}")
                return new_path
    return path

def iterate_and_shorten(directory, max_length, ellipsis, dry_run):
    for root, dirs, files in os.walk(directory, topdown=False):
        for dname in dirs:
            dpath = os.path.join(root, dname)
            shortened_path = shorten_path(dpath, max_length, ellipsis, dry_run)
            dirs[dirs.index(dname)] = os.path.basename(shortened_path)

        for fname in files:
            fpath = os.path.join(root, fname)
            shorten_path(fpath, max_length, ellipsis, dry_run)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Shorten long filenames and directory names.")
    parser.add_argument('directory', help="The directory to process.")
    parser.add_argument('-n', '--length', type=int, default=100, help="The maximum allowable length for directory or file names.")
    parser.add_argument('--ellipsis', default="...", help="The ellipsis to use when shortening.")
    parser.add_argument('--dry', action="store_true", help="Dry run mode, only log what would be renamed without actual renaming.")
    args = parser.parse_args()

    iterate_and_shorten(args.directory, args.length, args.ellipsis, args.dry)