#!/usr/bin/env bash ################################################################################ # # Rename Special Characters to Underscores # # Skript zum Ersetzen von Sonderzeichen (|, <, >, /, \, *, ?, ") durch # Unterstriche (_) in Datei- und Ordnernamen unter macOS und Linux # # Dieses Skript durchsucht rekursiv einen angegebenen Ordner und benennt # alle Dateien und Unterordner um, die problematische Sonderzeichen enthalten. # Dabei werden mehrfache Unterstriche und ungewollte Leerzeichen vermieden. # # Kompatibilität: macOS und Linux # # Copyright (c) 2025 Dominik Höfling # # Dieses Programm ist freie Software. Sie können es unter den Bedingungen # der GNU General Public License, wie von der Free Software Foundation # veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß # Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren Version. # # Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, dass es # Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne # die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN # BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. # # Sie sollten ein Exemplar der GNU General Public License zusammen mit # diesem Programm erhalten haben. Falls nicht, siehe # . # ################################################################################ # Farben für bessere Lesbarkeit RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Standardwerte DRY_RUN=false TARGET_DIR="" # Hilfefunktion show_help() { echo "Verwendung: $0 [OPTIONEN] ZIELORDNER" echo "" echo "Ersetzt Sonderzeichen (|, <, >, /, \\, *, ?, \") durch Unterstriche (_)" echo "in allen Datei- und Ordnernamen." echo "" echo "Optionen:" echo " -d, --dry-run Testlauf ohne tatsächliche Umbenennung" echo " -h, --help Diese Hilfe anzeigen" echo "" echo "Kompatibilität: macOS und Linux" echo "" echo "Beispiel:" echo " $0 -d ~/Dokumente/MeinOrdner # Testlauf" echo " $0 ~/Dokumente/MeinOrdner # Tatsächliche Umbenennung" } # Funktion zum Bereinigen des Dateinamens clean_name() { local name="$1" # 1. Ersetze alle Varianten von Sonderzeichen mit Leerzeichen # Behandelt: |, <, >, /, \, *, ?, " mit optionalen Leerzeichen darum name=$(echo "$name" | sed -E 's# *[|<>/\\*?"]+ *# #g') # 2. Ersetze verbleibende Sonderzeichen durch Leerzeichen name=$(echo "$name" | tr '|<>/\\*?"' ' ') # 3. Ersetze mehrfache Leerzeichen durch einzelnes Leerzeichen name=$(echo "$name" | sed -E 's/ +/ /g') # 4. Entferne Leerzeichen am Anfang und Ende name=$(echo "$name" | sed -E 's/^ +//; s/ +$//') # 5. Ersetze Leerzeichen durch Unterstrich name=$(echo "$name" | tr ' ' '_') # 6. Ersetze mehrfache Unterstriche durch einzelnen Unterstrich name=$(echo "$name" | sed -E 's/_+/_/g') # 7. Entferne Unterstriche am Anfang und Ende name=$(echo "$name" | sed -E 's/^_+//; s/_+$//') echo "$name" } # Funktion zum Umbenennen rename_item() { local path="$1" local dir=$(dirname "$path") local old_name=$(basename "$path") local new_name=$(clean_name "$old_name") # Nur umbenennen, wenn sich der Name geändert hat if [ "$old_name" != "$new_name" ]; then local new_path="$dir/$new_name" if [ "$DRY_RUN" = true ]; then echo -e "${YELLOW}[TEST]${NC} $old_name → $new_name" else # Prüfe, ob Ziel bereits existiert if [ -e "$new_path" ]; then echo -e "${RED}[FEHLER]${NC} Ziel existiert bereits: $new_name" return 1 fi # Führe Umbenennung durch if mv "$path" "$new_path"; then echo -e "${GREEN}[OK]${NC} $old_name → $new_name" else echo -e "${RED}[FEHLER]${NC} Konnte nicht umbenennen: $old_name" return 1 fi fi fi } # Parameter verarbeiten while [[ $# -gt 0 ]]; do case $1 in -d|--dry-run) DRY_RUN=true shift ;; -h|--help) show_help exit 0 ;; *) TARGET_DIR="$1" shift ;; esac done # Prüfe, ob Zielordner angegeben wurde if [ -z "$TARGET_DIR" ]; then echo -e "${RED}Fehler: Kein Zielordner angegeben.${NC}" echo "" show_help exit 1 fi # Prüfe, ob Zielordner existiert if [ ! -d "$TARGET_DIR" ]; then echo -e "${RED}Fehler: Ordner existiert nicht: $TARGET_DIR${NC}" exit 1 fi # Zeige Modus an if [ "$DRY_RUN" = true ]; then echo -e "${YELLOW}=== TESTMODUS - Keine tatsächlichen Änderungen ===${NC}" else echo -e "${GREEN}=== PRODUKTIVMODUS - Dateien werden umbenannt ===${NC}" echo -e "${YELLOW}Warnung: Erstellen Sie vorher ein Backup!${NC}" read -p "Fortfahren? (j/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Jj]$ ]]; then echo "Abgebrochen." exit 0 fi fi echo "" echo "Durchsuche: $TARGET_DIR" echo "" # Zähler count_renamed=0 count_errors=0 # Verwende find mit depth-first (tiefste Ebene zuerst) # Dies verhindert Probleme beim Umbenennen von Elternordnern while IFS= read -r -d '' item; do if rename_item "$item"; then ((count_renamed++)) else ((count_errors++)) fi done < <(find "$TARGET_DIR" -depth -print0 | grep -zE '[|<>/\\*?"]') # Zusammenfassung echo "" echo "=== Zusammenfassung ===" if [ "$DRY_RUN" = true ]; then echo "Würde $count_renamed Elemente umbenennen" else echo "Umbenannte Elemente: $count_renamed" fi echo "Fehler: $count_errors" echo "" if [ "$DRY_RUN" = true ]; then echo -e "${YELLOW}Führen Sie das Skript ohne -d aus, um tatsächlich umzubenennen.${NC}" fi