import os import shutil import argparse def parse_args(): parser = argparse.ArgumentParser(description="Sort files by extension into subfolders") parser.add_argument("source", help="Directory to scan") parser.add_argument("dest", help="Destination directory") parser.add_argument("--ext", nargs="+", required=True, help="Extensions to match e.g. jpg png") parser.add_argument("--dry-run", action="store_true", help="Preview only, no files moved") return parser.parse_args() def scan_and_move(source, dest, extensions, dry_run): extensions = [e.lower().lstrip(".") for e in extensions] matched = 0 for root, dirs, files in os.walk(source): for file in files: ext = os.path.splitext(file)[1].lower().lstrip(".") if ext in extensions: src_path = os.path.join(root, file) dest_dir = os.path.join(dest, ext) dest_path = os.path.join(dest_dir, file) print(f"{'[DRY RUN] ' if dry_run else ''}Moving: {src_path} → {dest_path}") if not dry_run: os.makedirs(dest_dir, exist_ok=True) shutil.move(src_path, dest_path) matched += 1 print(f"\nDone. {matched} file(s) matched.") if __name__ == "__main__": args = parse_args() scan_and_move(args.source, args.dest, args.ext, args.dry_run)