Ich weiß, dass es nicht genau das ist, was Sie wollten, aber wenn Sie die ursprüngliche Codierung kennen, können Sie vielleicht convmv
verwenden um die Kodierung auf UTF-8 zu ändern, was die meisten Probleme beheben sollte.
Dies hat bei mir bei einem Ordner mit einigen ungültig codierten polnischen Dateinamen funktioniert:
convmv -f cp1250 -t utf8 -r .
Beachten Sie, dass dieser Befehl eigentlich nichts umbenennt; --notest
hinzufügen Möglichkeit, die Dateien wirklich umzubenennen.
Sie werden einige Probleme bekommen, wenn Sie Dateien und umbenennen wollen Verzeichnisse gleichzeitig. Nur eine Datei umzubenennen ist einfach genug. Aber Sie möchten sicherstellen, dass die Verzeichnisse auch umbenannt werden. Sie können nicht einfach mv Motörhead/Encöding Motorhead/Encoding
seit Motorhead
wird zum Zeitpunkt des Aufrufs nicht existieren.
Wir müssen also zuerst alle Dateien und Ordner mit der Tiefe durchlaufen und dann nur die aktuelle Datei oder den aktuellen Ordner umbenennen. Folgendes funktioniert mit GNU find
und 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 Regex ändern, indem Sie new="${f//[\\\/\:\*\?\"<>|]/}"
verwenden wenn Sie etwas ersetzen möchten, was Windows nicht verarbeiten kann.
Speichern Sie dieses Skript unter rename.sh
, machen Sie es mit chmod +x rename.sh
ausführbar . Nennen Sie es dann wie rename.sh /some/path
.
Stellen Sie sicher, dass Dateinamenkonflikte behoben werden („Notice
” Ankündigungen).
Wenn Sie sich absolut sicher sind es die richtigen Ersetzungen vornimmt, entfernen Sie den echo
aus dem Skript, um Dinge tatsächlich umzubenennen, anstatt nur zu drucken, was es tut.
Sicherheitshalber würde ich empfehlen, dies zuerst an einer kleinen Teilmenge von Dateien zu testen.
Optionen erklärt
Um zu erklären, was hier vor sich geht:
-depth
stellt sicher, dass Verzeichnisse mit der Tiefe zuerst rekursiv sind, sodass wir alles vom Ende "aufrollen" können. Normalerweisefind
geht anders (aber nicht in der Breite zuerst).-print0
sorgt für denfind
Die Ausgabe ist durch Null getrennt, sodass wir sie mitread -d ''
lesen können infile
Variable. Das hilft uns, mit allen Arten von seltsamen Dateinamen umzugehen, einschließlich solchen mit Leerzeichen und sogar Zeilenumbrüchen.- Wir bekommen das Verzeichnis der Datei mit
dirname
. Vergessen Sie nicht, Ihre Variablen immer richtig in Anführungszeichen zu setzen, sonst würde jeder Pfad mit Leerzeichen oder Globbing-Zeichen dieses Skript beschädigen. - Wir erhalten den tatsächlichen Dateinamen (oder Verzeichnisnamen) mit
basename
. - Dann entfernen wir alle ungültigen Zeichen aus
$f
Verwenden der String-Ersetzungsfunktionen von Bash. Ungültig bedeutet alles, was kein Klein- oder Großbuchstabe, eine Ziffer, ein Schrägstrich (\/
), ein Punkt (\.
), ein Unterstrich oder ein Minus-Bindestrich. - Falls
$f
bereits sauber ist (der bereinigte Name ist identisch mit dem aktuellen Namen), überspringe ihn. - Falls
$new
existiert bereits im Verzeichnis$d
(Beispiel:Sie haben Dateien mit dem Namenresume
undrésumé
im selben Verzeichnis), eine Warnung ausgeben. Sie möchten es nicht umbenennen, da auf einigen Systemenmv foo foo
verursacht ein Problem. Ansonsten - Wir benennen schließlich die ursprüngliche Datei (oder das Verzeichnis) in ihren neuen Namen um
Da dies nur auf die tiefste Hierarchie wirkt, wird Motörhead/Encöding
umbenannt bis Motorhead/Encoding
erfolgt in zwei Schritten:
mv Motörhead/Encöding Motörhead/Encoding
mv Motörhead Motorhead
Dadurch wird sichergestellt, dass alle Ersetzungen in der richtigen Reihenfolge durchgeführt werden.
Beispieldateien und Testlauf
Nehmen wir an, einige Dateien befinden sich in einem Basisordner namens 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 einer Ausführung im Debug-Modus (mit dem echo
vor der mv
), d. h. die Befehle, die aufgerufen 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 das Fehlen von Nachrichten für with-hyphen.txt
, schedule
, und test
selbst.