Skip to content

Instantly share code, notes, and snippets.

@hemna
Last active May 8, 2025 12:20
Show Gist options
  • Save hemna/573d384dd84fea8527ad7b65853f1c3e to your computer and use it in GitHub Desktop.
Save hemna/573d384dd84fea8527ad7b65853f1c3e to your computer and use it in GitHub Desktop.
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
# "rich",
# ]
# ///
import os
import shutil
import string
import sys
import argparse
from rich.progress import Progress
from collections import defaultdict
def organize_by_alpha(target_dir, dry_run=False):
# Ensure the target directory exists
if not os.path.isdir(target_dir):
print(f"Error: {target_dir} is not a valid directory.")
return
# Define valid subfolder names (A-Z, 0-9)
valid_folders = list(string.ascii_uppercase) + list(string.digits)
subfolder_set = {os.path.join(target_dir, name) for name in valid_folders}
# Gather items to process (skip hidden files/dirs and alpha/number subfolders)
items = [
f for f in os.listdir(target_dir)
if not f.startswith('.')
and os.path.join(target_dir, f) not in subfolder_set
]
total_items = len(items)
if total_items == 0:
print("No files or folders to process.")
return
# Determine which directories are needed
items_by_letter = defaultdict(list)
for name in items:
first_char = name[0].upper()
if first_char in valid_folders:
items_by_letter[first_char].append(name)
# Create only needed subfolders
for folder, folder_items in items_by_letter.items():
subfolder = os.path.join(target_dir, folder)
if not os.path.exists(subfolder):
if dry_run:
print(f"Would create folder: {subfolder}")
else:
os.makedirs(subfolder, exist_ok=True)
with Progress() as progress:
task = progress.add_task("Organizing items", total=total_items)
for name in items:
path = os.path.join(target_dir, name)
first_char = name[0].upper()
if first_char in valid_folders:
dest_folder = os.path.join(target_dir, first_char)
dest_path = os.path.join(dest_folder, name)
if dry_run:
progress.console.print(f"[yellow]Would move {name} -> {dest_folder}/[/yellow]")
else:
progress.console.print(f"[green]Moving {name} -> {dest_folder}/[/green]")
shutil.move(path, dest_path)
else:
progress.console.print(f"[red]Skipping {name}: does not start with A-Z or 0-9.[/red]")
progress.update(task, advance=1)
def main():
parser = argparse.ArgumentParser(description="Organize files and folders into A-Z and 0-9 subfolders.")
parser.add_argument("directory", help="Target directory to organize")
parser.add_argument("--dry-run", action="store_true", help="Show what would be done without moving files or folders")
args = parser.parse_args()
organize_by_alpha(args.directory, dry_run=args.dry_run)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment