move-no-collisions-recurse.py hinzugefügt
This commit is contained in:
parent
bca74a9a4b
commit
0f867a5f8b
1 changed files with 112 additions and 0 deletions
112
move-no-collisions-recurse.py
Normal file
112
move-no-collisions-recurse.py
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def get_new_filename(dest_path: Path, filename: str) -> Path:
|
||||||
|
"""Generate a new filename if a collision occurs by adding -01, -02, etc."""
|
||||||
|
name = Path(filename).stem
|
||||||
|
suffix = Path(filename).suffix
|
||||||
|
counter = 1
|
||||||
|
new_path = dest_path / filename
|
||||||
|
|
||||||
|
while new_path.exists():
|
||||||
|
new_filename = f"{name}-{counter:02d}{suffix}"
|
||||||
|
new_path = dest_path / new_filename
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
return new_path
|
||||||
|
|
||||||
|
def move_files(source_dir: str, dest_dir: str, extensions: list, dry_run: bool = False) -> tuple:
|
||||||
|
"""
|
||||||
|
Move files with specific extensions from source_dir to dest_dir.
|
||||||
|
Returns tuple of (files_processed, total_size)
|
||||||
|
"""
|
||||||
|
source_path = Path(source_dir).resolve()
|
||||||
|
dest_path = Path(dest_dir).resolve()
|
||||||
|
files_processed = 0
|
||||||
|
total_size = 0
|
||||||
|
|
||||||
|
if not source_path.exists():
|
||||||
|
print(f"Error: Source directory '{source_dir}' does not exist!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Create destination if it doesn't exist
|
||||||
|
if not dry_run:
|
||||||
|
dest_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Convert extensions to lowercase for case-insensitive matching
|
||||||
|
extensions = [ext.lower() for ext in extensions]
|
||||||
|
|
||||||
|
# Walk through source directory and all subdirectories
|
||||||
|
for root, _, files in os.walk(source_path):
|
||||||
|
for file in files:
|
||||||
|
file_path = Path(root) / file
|
||||||
|
if file_path.suffix.lower() in extensions:
|
||||||
|
files_processed += 1
|
||||||
|
total_size += file_path.stat().st_size
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print(f"Would move: {file_path} -> {dest_path / file}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get new filename if collision occurs
|
||||||
|
new_path = get_new_filename(dest_path, file)
|
||||||
|
|
||||||
|
# Move file and preserve timestamps
|
||||||
|
shutil.copy2(file_path, new_path)
|
||||||
|
os.remove(file_path)
|
||||||
|
|
||||||
|
print(f"Moved: {file_path} -> {new_path}")
|
||||||
|
|
||||||
|
return files_processed, total_size
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Move files with specific extensions from source directory to destination directory"
|
||||||
|
)
|
||||||
|
parser.add_argument("source", nargs="?", help="Source directory")
|
||||||
|
parser.add_argument("destination", nargs="?", help="Destination directory")
|
||||||
|
parser.add_argument(
|
||||||
|
"-ext",
|
||||||
|
"--extensions",
|
||||||
|
nargs="+",
|
||||||
|
help="File extensions to move (e.g., .jpg .png .gif)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-dry",
|
||||||
|
"--dry-run",
|
||||||
|
action="store_true",
|
||||||
|
help="Perform a dry run without moving files"
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not all([args.source, args.destination, args.extensions]):
|
||||||
|
parser.print_help()
|
||||||
|
print("\nExample usage:")
|
||||||
|
print(" move_files.py /source/dir /dest/dir -ext .jpg .png .gif")
|
||||||
|
print(" move_files.py /source/dir /dest/dir -ext .jpg -dry")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Ensure extensions start with dot
|
||||||
|
extensions = [ext if ext.startswith('.') else f'.{ext}' for ext in args.extensions]
|
||||||
|
|
||||||
|
files_processed, total_size = move_files(
|
||||||
|
args.source,
|
||||||
|
args.destination,
|
||||||
|
extensions,
|
||||||
|
args.dry_run
|
||||||
|
)
|
||||||
|
|
||||||
|
# Print summary
|
||||||
|
action = "Would move" if args.dry_run else "Moved"
|
||||||
|
print(f"\nSummary:")
|
||||||
|
print(f"Files {action}: {files_processed}")
|
||||||
|
print(f"Total size: {total_size / 1024 / 1024:.2f} MB")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Add table
Reference in a new issue