Wie kann man Dateien mit ungültiger Kodierung massenweise umbenennen oder ungültige kodierte Zeichen massenweise ersetzen?

15

Ich habe einen Debian-Server und hoste Musik für einen Internetradiosender. Ich habe Probleme mit Dateinamen und -pfaden, weil viele Dateien eine ungültige Kodierung haben, zum Beispiel:

./music/Bändname - Some Title - additional Info/B�ndname - 07 - This Title Is Cörtain, The EncÃding Not.mp3

Im Idealfall möchte ich alles entfernen, was nicht aus Buchstaben A-Z/ a-zoder Zahlen 0-9oder Bindestrich -/ Unterstrich besteht _... Das Ergebnis sollte ungefähr so ​​aussehen:

./music/Bndname-SomeTitle-additionalInfo/Bndname-07-ThisTitleIsCrtain,TheEncdingNot.mp3

Wie kann dies für einen Stapel vieler Dateien und Verzeichnisse erreicht werden?

Ich habe diese ähnliche Frage gesehen: Bulk-Umbenennung (oder korrekte Anzeige) von Dateien mit Sonderzeichen

Aber dies behebt nur die Kodierung, ich würde einen strengeren Ansatz wie oben beschrieben bevorzugen.

Afr
quelle

Antworten:

14

Es kann zu Problemen kommen, wenn Sie Dateien und Verzeichnisse gleichzeitig umbenennen möchten . Nur eine Datei umzubenennen ist einfach genug. Sie möchten jedoch sicherstellen, dass die Verzeichnisse auch umbenannt werden. Sie können nicht einfach mv Motörhead/Encöding Motorhead/Encodingda Motorheadzum Zeitpunkt des Anrufs nicht existieren.

Wir müssen also zuerst alle Dateien und Ordner gründlich durchlaufen und dann nur die aktuelle Datei oder den aktuellen Ordner umbenennen. Das Folgende funktioniert mit GNU findund Bash 4.2.42 auf meinem OS X.

#!/usr/bin/env bash
find "$1" -depth -print0 | while IFS= read -r -d '' file; do
  d="$( dirname "$file" )"
  f="$( basename "$file" )"
  new="${f//[^a-zA-Z0-9\/\._\-]/}"
  if [ "$f" != "$new" ]      # if equal, name is already clean, so leave alone
  then
    if [ -e "$d/$new" ]
    then
      echo "Notice: \"$new\" and \"$f\" both exist in "$d":"
      ls -ld "$d/$new" "$d/$f"
    else
      echo mv "$file" "$d/$new"      # remove "echo" to actually rename things
    fi
  fi
done

Sie können den regulären Ausdruck ändern, indem Sie verwenden, new="${f//[\\\/\:\*\?\"<>|]/}"wenn Sie alles ersetzen möchten, was Windows nicht verarbeiten kann.

Speichern Sie dieses Skript als rename.sh, und machen Sie es mit ausführbar chmod +x rename.sh. Dann nenne es wie rename.sh /some/path.

Stellen Sie sicher, dass Kollisionen von Dateinamen (" Notice" Ansagen) behoben werden.

Wenn Sie absolut sicher sind, dass es die richtigen Ersetzungen vornimmt, entfernen Sie das Symbol echoaus dem Skript , um die Objekte tatsächlich umzubenennen, anstatt nur zu drucken, was es tut.

Aus Sicherheitsgründen würde ich empfehlen, dies zunächst an einer kleinen Teilmenge von Dateien zu testen.


Optionen erklärt

Um zu erklären, was hier vor sich geht:

  • -depthwird sicherstellen, dass Verzeichnisse mit der Tiefe zuerst rekursiv behandelt werden, damit wir alles vom Ende an "zusammenfassen" können. Normalerweise findwird anders überquert (aber nicht in der Breite zuerst).
  • -print0Stellt sicher, dass die findAusgabe durch Nullen getrennt ist, damit wir sie read -d ''in die fileVariable einlesen können . Auf diese Weise können wir mit allen Arten von seltsamen Dateinamen umgehen, auch mit Leerzeichen und sogar mit Zeilenumbrüchen.
  • Wir werden das Verzeichnis der Datei mit bekommen dirname. Vergessen Sie nicht, Ihre Variablen immer korrekt in Anführungszeichen zu setzen, da sonst ein Pfad mit Leerzeichen oder glühenden Zeichen dieses Skript beschädigen würde.
  • Wir erhalten den tatsächlichen Dateinamen (oder Verzeichnisnamen) mit basename.
  • Anschließend entfernen wir alle ungültigen Zeichen aus der $fVerwendung von Bashs Funktionen zum Ersetzen von Zeichenfolgen. Ungültig bedeutet, dass es sich nicht um einen Klein- oder Großbuchstaben, eine Ziffer, einen Schrägstrich ( \/), einen Punkt ( \.), einen Unterstrich oder einen Minus-Bindestrich handelt.
  • Wenn $fes bereits sauber ist (der gereinigte Name ist identisch mit dem aktuellen Namen), überspringen Sie ihn.
  • Wenn $newdas Verzeichnis bereits vorhanden ist $d(z. B. Sie haben Dateien mit dem Namen resumeund résuméim selben Verzeichnis), geben Sie eine Warnung aus. Sie möchten es nicht umbenennen, da dies auf einigen Systemen mv foo foozu Problemen führt. Andernfalls,
  • Wir benennen die ursprüngliche Datei (oder das ursprüngliche Verzeichnis) schließlich in ihren neuen Namen um

Da dies nur auf die tiefste Hierarchie angewendet wird, erfolgt die Umbenennung Motörhead/Encödingin Motorhead/Encodingin zwei Schritten:

  1. mv Motörhead/Encöding Motörhead/Encoding
  2. mv Motörhead Motorhead

Dadurch wird sichergestellt, dass alle Ersetzungen in der richtigen Reihenfolge erfolgen.


Beispieldateien und Testlauf

Nehmen wir an, einige Dateien in einem Basisordner mit dem Namen test:

test
test/Motörhead
test/Motörhead/anöther_file.mp3
test/Motörhead/Encöding
test/Randöm
test/Täst
test/Täst/Töst
test/with space
test/with-hyphen.txt
test/work
test/work/resume
test/work/résumé
test/work/schedule

Hier ist die Ausgabe eines Laufs im Debug-Modus (mit dem echovor dem mv), dh die Befehle, die aufgerufen werden würden, und die Kollisionswarnungen:

mv test/Motörhead/anöther_file.mp3 test/Motörhead/another_file.mp3
mv test/Motörhead/Encöding test/Motörhead/Encoding
mv test/Motörhead test/Motorhead
mv test/Randöm test/Random
mv test/Täst/Töst test/Täst/Tost
mv test/Täst test/Tast
mv test/with space test/withspace
Notice: "resume" and "résumé" both exist in test/work:
-rw-r—r--  …  …  test/work/resume
-rw-r—r--  …  …  test/work/résumé

Beachten Sie die Abwesenheit von Nachrichten für with-hyphen.txt, scheduleund testselbst.

slhck
quelle
1
Möglicherweise möchten Sie Logik hinzufügen, um den Fall zu behandeln, in dem das Ziel des mvbereits vorhanden ist. Dies kann passieren (1), wenn Sie Dateien haben, die bereits bereinigt sind (was zu führt mv foo foo), oder (2), wenn Sie Dateien mit dem gleichen Namen außer haben für die Sonderzeichen (zB mv Encöding Encodingwo Sie Encodingzusätzlich zuEncöding ).
Scott
Gute Idee, danke. Irgendwelche konkreten Vorschläge, was in diesem Fall zu tun ist? Zugegeben - dies auf saubere und vernünftige Weise zu erreichen ist schwieriger als es zunächst scheint. Wenn Sie etwas haben, können Sie es natürlich gerne bearbeiten.
Slhck
Ich glaube nicht, dass es sinnvoll ist, über die automatische Behandlung von Kollisionen nachzudenken - identifizieren Sie sie einfach dem Benutzer und lassen Sie ihn mit ihnen umgehen. Ich habe Ihre Antwort bearbeitet, wie Sie vorgeschlagen haben.
Scott
+1 für die Verwendung des Beispiels mit "Encöding" Zu viel Fön! :-)
Marcel
Nach drei Jahren komme ich immer noch hierher zurück. so nützlich! :-)
Afr
15

Ich weiß, dass es nicht genau das ist, was Sie wollten, aber wenn Sie die ursprüngliche Codierung kennen, können Sie möglicherweise convmvdie Codierung in UTF-8 ändern, was die meisten Probleme beheben sollte.

Dies funktionierte für mich in einem Ordner mit einigen ungültig codierten polnischen Dateinamen:

convmv -f cp1250 -t utf8 -r .

Beachten Sie, dass dieser Befehl nichts umbenennt. --notestOption hinzufügen , um die Dateien wirklich umzubenennen.

mik01aj
quelle
1
Für diejenigen, die einen statischen Satz haben (oder keinen abwechslungsreichen Zeichensatzmix haben), ist die convmvOption erstaunlich einfach und perfekt. Bei OP mit einer potenziellen Vielzahl von Zeichensätzen könnte dies mit der anderen Antwort zusammengeführt werden, da convmvoffenbar bekannt ist, wann es das richtige Format aufweist oder wann es nicht. Durch Durchlaufen der Zeichensätze über convmv --listwürde man sie richtig codieren.
1
Damit meine ich, wenn als OP ein Debian-Server läuft, würde man heutzutage sicherlich UTF8 annehmen. In diesem Fall kann man die Originalbuchstaben behalten. Ich hatte den Ordner a mit einigen nordischen Zeichen und benutzte: convmv -t utf8 --nfc -f iso-8859-1 --notest -r .- Das --nfcwar vor OS X Linux-konform zu sein oder so, durch einfaches Eingeben convmvwerden die (nützlichen) Optionen aufgegeben.
0

Ich weiß, Sie haben nach dem Umbenennen gefragt.

Mit Software wie MusicBrainz Picard können Sie dem Problem jedoch ganz einfach ausweichen .

Es ist in der Lage, Musik zu identifizieren (Audio-Fingerabdruck), alle erforderlichen Daten (einschließlich Titelbilder, sofern verfügbar) aus der riesigen MusicBrainz- Datenbank herunterzuladen und die Dateien so zu verschieben, dass Ihre Sammlung zu jedem beliebigen Muster passt. Ich benutze es seit Jahren und es funktionierte immer perfekt mit allem von Kyrillisch bis Arabisch; und natürlich (zumindest für lateinische Skripte) kann es auch die Konvertierung nach ASCII durchführen.

Bei diesem Ansatz spielt es keine Rolle, wie unordentlich / schlecht Ihre Sammlung wirklich benannt ist, solange die Dateien lesbar und vollständig sind.

(Habe ich schon erwähnt, dass es kostenlos ist? Sowohl in der Redefreiheit als auch im Freibier? Sowohl in der Software als auch in der Datenbank ..?)

Alois Mahdal
quelle