#!/bin/bash # Handle --dry-run flag DRY_RUN=0 if [ "$1" = "--dry-run" ]; then DRY_RUN=1 shift fi # Directory to process (default: current directory) DIR="." if [ -n "$1" ]; then DIR="$1" fi # Function to process and rename a file process_file() { local original="$1" local base ext modified sanitized_base # Skip directories and non-regular files [ -f "$original" ] || return 0 # Split base and extension if [[ "$original" == *.* ]]; then ext=".${original##*.}" base="${original%.*}" else base="$original" ext="" fi # Sanitize base only, not the extension sanitized_base=$(echo "$base" | tr ' ' '_' | tr '[:upper:]' '[:lower:]') sanitized_base=$(echo "$sanitized_base" | sed 's/[^a-zA-Z0-9._-]//g') # Truncate base to 250 chars to avoid hitting filesystem limits base_truncated="${sanitized_base:0:250}" # Rebuild filename with sanitized base and original extension modified="$base_truncated$ext" # Collapse multiple underscores modified=$(echo "$modified" | tr -s '_') # Trim leading/trailing underscores modified=$(echo "$modified" | sed 's/^_//' | sed 's/_$//') # Skip if empty if [ -z "$modified" ]; then echo "Error: Empty filename after sanitizing '$original'" >&2 return 1 fi # Skip if no change if [ "$original" = "$modified" ]; then echo "No changes needed: '$original'" return 0 fi # Collision handling counter=1 original_modified="$modified" while [ -e "$modified" ]; do modified="${base_truncated}_${counter}${ext}" # Truncate again to avoid going over 255 chars modified="${modified:0:255}" ((counter++)) done # Dry run if [ "$DRY_RUN" -eq 1 ]; then echo "Dry-run: Would rename '$original' → '$modified'" return 0 fi # Rename file if mv -- "$original" "$modified"; then echo "Renamed: '$original' → '$modified'" else echo "Error: Failed to rename '$original'" >&2 return 1 fi } # Enter target directory cd "$DIR" || { echo "Error: Failed to change directory to '$DIR'" >&2; exit 1; } # Process all non-hidden files for file in *; do process_file "$file" done # Optional: process hidden files (uncomment below) # for file in .??*; do # process_file "$file" # done