Zunächst mal bin ich der Meinung, dass solche Endlos-Threads eigentlich keine gute Idee sind.
Che hat geschrieben: 11.05.2019 03:03:27
1. Muss mehrfach ausgeführt werden, bis alles ersetzt ist:
Code: Alles auswählen
find ./ -execdir rename 's/ä/ae/;s/ö/oe/;s/ü/ue/;s/Ä/Ae/;s/Ö/Oe/;s/Ü/Ue/;s/ß/ss/;s/é/e/;s/ó/o/;s/í/i/;s/ú/u/;s/á/a/;s/ã/a/;s/Ê/E/;s/ê/e/;s/à/a/;s/è/e/;s/â/a/;s/õ/o/;s/ô/o/;s/Á/A/;s/Ò/O/;s/Ã/A/' -v {} \;
Das liegt an 2 Punkten:
1. ersetzt sowas
nur das erste Vorkommen von ä im Dateinamen. Hat der Dateiname 3 ä im Namen, dann musst du die Routine 3 mal laufen lassen. Abhilfe schafft die globale Ersetzung:
Für einzelne Zeichen (im Such- und Erstzungsabschnitt) bietet sich die y///-Erstzung an, welche nach der Position im Abschnitt das entsprechende Pendant, direkt global ersetzt. Wird ein Zeichen durch 2 Zeichen ersetzt, oder andersrum, dann bleibt lediglich s///g.
2. liegt das an der Funktionsweise von find. Dir wird vermutlich aufgefallen sein, dass dort häufiger "Verzeichnis nicht gefunden" (oder Vergleichbares) aufgetreten ist. Find erstellt in einem Rutsch diese Liste und bearbeitet sie dann von oben nach unten ab. Meinetwegen wäre die Ergebnisliste sowas:
Dann würde das erste rename das Verzeichnis "./Ä" ändern und das danach folgende rename würde aber die Datei "./Ä/ä.txt" nicht finden, da das Verzeichnis ja inzwischen umbenannt wurde und gar nicht mehr existiert. Der nächste Find-Lauf würde dann die Datei "./Ae/ä.txt" finden und rename würde ändern. Was du benötigst wäre eine Ausgabeliste in dieser Form:
Dass die Dateien vor den Verzeichnissen ausgegeben werden, damit die Abarbeitung von oben nach unten durchlaufen kann. Das erreichst du durch den find-Parameter "-depth".
Wenn man das alles kombiniert und zusätzlich noch den Verbose-Schalter von rename an die richtige Stelle setzt (damit du auch was siehst) und dann noch den Turbo von find zündet, in dem man rename eine Argumentliste (+ anstatt \;) übergibt und damit nur insgesamt einen (sofern die Liste nicht zu lang ist), anstatt für jeden Dateinamen einen eigenen Rename-Prozess startet, dann sollte sowas in einem Rutsch performant durchlaufen:
Code: Alles auswählen
find ./ -depth -execdir rename -v 's/ä/ae/g;s/ö/oe/g;s/ü/ue/g;s/Ä/Ae/g;s/Ö/Oe/g;s/Ü/Ue/g;s/ß/ss/g;y/éóíúáãÊêàèâõôÁÒÃ/eoiuaaEeaeaooAOA/' {} +
2. Eine Ausführung reicht. Der Befehl "1." soll unbedingt vorher erfolgreich angewandt worden sein, sonst werden z.B. Zeichen mit Umlaut hier durch "_" ersetzt:
Nur schade, dass ich diesen Befehl bisher nicht zum rekursiven Verhalten überreden konnte, Grund warum ich ihn in jefem Unterverzeichnis extra ausführen muss. Kennt jemand eine Lösung dafür?
Das funktioniert deswegen nicht, weil rename nicht rekursiv arbeitet, sondern nur die Argumente bearbeitet, die du übergibst (hier mit * die Dateien im aktuellen Verzeichnis). Man könnte die Argumente also ebenfalls mit find übergeben. Bei sowas wäre ich allerdings ziemlich vorsichtig, denn hier werden unterschiedliche Zeichen durch ein einziges Zeichen ersetzt, was womöglich Dubletten erzeugen will und damit Fehler hervorrufen dürfte.
3. Verbleibende "." und mehrfach nebeneinander stehende "_" werden hiermit auf einem einzigen "_" versetzt:
Code: Alles auswählen
find ./ -execdir rename 's/\.\_/\_/;s/\_\_/\_/' -v {} \;
Ein _ muss nicht gequotet werden und im Ersetzungsteil wird alles literal behandelt. Zudem kommt dieses rename ja von Perl, kann also mit + mehrere Zeichen ansprechen:
Noch offene Wüsche:
1. Jedem Befehl bei der Ausführung mitteilen, wie oft er ausgeführt werden soll. Vor allem beim 1. muss man mehrfach den Vorgang wiederholen. Da würde ich gerne ihm sagen können, mache jetzt 10 Durchläufe und dann höre auf.
Sollte obsolet sein!?
2. Dann die drei Befehle in einer einzigen Zeile packen (mein Wunsch "1." berücksichtigt), sodass der Befehl-Bündel nur einmal ausgeführt werden müsste. Das würde sehr hilfreich sein
Mir ist zwar nicht klar, warum das notwendig sein sollte, aber das gibt's mehrere Möglichkeiten: Du kannst die Befehle durch einen Strichpunkt trennen, dann werden die folgenden Befehle ausgeführt, wenn die davorstehenden Befehle abgearbeitet sind, unabhängig davon, ob erfolgreich oder nicht. Oder du kannst die Befehle mit && verketten, dann wird der folgende Befehl abgearbeitet, wenn der davorstehende Befehl erfolgreich (fehlerlos) abgearbeitet wurde. Oder in find direkt - find verkettet automatisch und wenn nicht anders angegeben mittels UND. Bedeutet, dass du einfach die sich unterscheidenden Teile (die -execdir) hintereinander aufführst:
Code: Alles auswählen
find ... +; find ... +
find ... + && find ... +
find ... -execdir ... + -execdir ... +
EDIT:
Die letzte Variante funktioniert natürlich nicht, wenn rename im 1. execdir angewendet wurde, da der dann aktuelle Dateiname ja nicht mehr in der Ergebnisliste auftaucht.