Bulk-Umbenennung (oder korrekte Anzeige) von Dateien mit Sonderzeichen

20

Ich habe eine Reihe von Verzeichnissen und Unterverzeichnissen, die Dateien mit Sonderzeichen enthalten, wie diese Datei:

robbie@phil:~$ ls testsktest.txt 
test?sktest.txt

Suchen zeigt eine Escape-Sequenz:

robbie@phil:~$ find testsktest.txt -ls 
424512 4000 -rwxr--r-x   1 robbie   robbie    4091743 Jan 26 00:34 test\323sktest.txt

Der einzige Grund, warum ich ihre Namen in die Konsole eingeben kann, ist der Tabulatorabschluss. Dies bedeutet auch, dass ich sie manuell umbenennen kann (und das Sonderzeichen entfernen kann).

Ich habe LC_ALL auf UTF-8 gesetzt, was anscheinend nicht hilft (auch nicht auf einer neuen Shell):

robbie@phil:~$ echo $LC_ALL
en_US.UTF-8

Ich verbinde mich mit ssh von meinem Mac mit dem Computer. Es ist eine Ubuntu-Installation:

robbie@phil:~$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=7.10
DISTRIB_CODENAME=gutsy
DISTRIB_DESCRIPTION="Ubuntu 7.10"

Shell ist Bash, TERM ist auf xterm-color gesetzt.

Diese Dateien gibt es schon eine ganze Weile und sie wurden nicht mit dieser Ubuntu-Installation erstellt. Ich weiß also nicht, wie die Einstellungen für die Systemcodierung waren.

Ich habe Dinge ausprobiert wie:

find . -type f -ls | sed 's/[^a-zA-Z0-9]//g'

Aber ich kann keine Lösung finden, die alles kann, was ich will:

  1. Identifizieren Sie alle Dateien mit nicht darstellbaren Zeichen (die oben genannten ignorieren viel zu viel).
  2. Führen Sie für alle diese Dateien in einem Verzeichnisbaum (rekursiv) mv oldname newname aus
  3. Optional besteht die Möglichkeit, Sonderzeichen wie ä in a zu transliterieren (nicht erforderlich, wäre aber genial)

ODER

  1. Alle diese Dateien korrekt anzeigen (und keine Fehler in Anwendungen, wenn Sie versuchen, sie zu öffnen)

Ich habe Teile und Stücke, wie alle Dateien durchlaufen und verschieben, aber die Dateien zu identifizieren und sie richtig für den Befehl mv zu formatieren, scheint der schwierige Teil zu sein.

Zusätzliche Informationen darüber, warum sie nicht korrekt angezeigt werden oder wie die richtige Codierung "erraten" werden kann, sind ebenfalls willkommen. (Ich habe convmv ausprobiert, aber es scheint nicht genau das zu tun, was ich will: http://j3e.de/linux/convmv/ )

RobbieV
quelle
Die folgende einfache Antwort folgt dem ersten Weg (finden Sie sie und benennen Sie sie in Ihre neue Kodierung um), aber der zweite Weg wäre auch interessant: Wenn Sie nun die Kodierung kennen, die für die entfernten Dateinamen verwendet wird, können Sie auf diese Weise zum entfernten Host sshen Wie werden die Dateinamen korrekt angezeigt (und können durch Eingabe ihrer Namen mit der Tastatur verwaltet werden)?
imz - Ivan Zakharyaschev

Antworten:

21

Ich vermute, Sie sehen dieses ungültige Zeichen, weil der Name eine Byte-Sequenz enthält, die nicht für UTF-8 gültig ist. Dateinamen in typischen Unix-Dateisystemen (einschließlich Ihres) sind Byte-Zeichenfolgen, und es liegt an den Anwendungen, zu entscheiden, welche Codierung verwendet wird. Heutzutage gibt es einen Trend zur Verwendung von UTF-8, der jedoch nicht universell ist, insbesondere in Gebieten, die niemals mit einfachem ASCII leben könnten und andere Codierungen verwendet haben, als es UTF-8 noch nicht gab.

Versuchen Sie herauszufinden LC_CTYPE=en_US.iso88591 ls, ob der Dateiname in ISO-8859-1 (Latin-1) Sinn macht. Wenn dies nicht der Fall ist, versuchen Sie es mit anderen Ländereinstellungen. Beachten Sie, dass hier nur die LC_CTYPELändereinstellung von Bedeutung ist.

In einem UTF-8-Gebietsschema werden mit dem folgenden Befehl alle Dateien angezeigt, deren Name nicht für UTF-8 gültig ist:

grep-invalid-utf8 () {
  perl -l -ne '/^([\000-\177]|[\300-\337][\200-\277]|[\340-\357][\200-\277]{2}|[\360-\367][\200-\277]{3}|[\370-\373][\200-\277]{4}|[\374-\375][\200-\277]{5})*$/ or print'
}
find | grep-invalid-utf8

Sie können mit recode oder iconv prüfen, ob sie in einem anderen Gebietsschema sinnvoller sind :

find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8

Wenn Sie festgestellt haben, dass eine Reihe von Dateinamen in einer bestimmten Codierung enthalten sind (z. B. latin1), können Sie sie auf eine Weise umbenennen

find | grep-invalid-utf8 |
rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;}
        $_=encode("utf8", $_)'

Dies verwendet den Perl- Umbenennungsbefehl , der unter Debian und Ubuntu verfügbar ist. Sie können es übergeben, um -nzu zeigen, was es tun würde, ohne die Dateien tatsächlich umzubenennen.

Gilles 'SO - hör auf böse zu sein'
quelle
Vielen Dank, ich werde einige dieser Dinge später heute versuchen! Sieht so aus, als wäre dies die akzeptierte Antwort :)
RobbieV
Der Fund | Der Befehl grep '[[: print:]]' scheint einfach alle Dateien zurückzugeben. Sollte UTF-8 nicht mit vielen anderen Kodierungen mit "normalen" Zeichen kompatibel sein?
RobbieV
@RobbieV: Ich habe getippt und wollte grep [^[:print:]]nach nicht druckbaren Zeichen suchen. Aber ich habe gerade mit GNU grep getestet und ungültige UTF-8-Sequenzen werden [^[:print:]]nicht erfasst (was Sinn macht, da sie keine nicht druckbaren Zeichen sind, sondern überhaupt keine Zeichen). Ich habe meinen Beitrag mit einer längeren Grepping-Methode für Zeilen mit ungültigen utf8-Sequenzen bearbeitet. Beachten Sie, dass ich auch die Richtung der recodeund iconvBeispiele festgelegt habe.
Gilles 'SO- hör auf böse zu sein'
Das hat einwandfrei funktioniert. Versuchte alle Befehle mit Ausnahme des Symbols v, und alle funktionieren wie erwartet. Pure Magie!
RobbieV
Sogar die vorgeschlagene latin1-Codierung war die richtige :)
RobbieV
1

Ich weiß, dass dies eine alte Frage ist, aber ich habe die ganze Nacht nach einer ähnlichen Lösung gesucht. Ich habe ein paar hilfreiche Tipps gefunden, aber sie haben nicht genau das getan, was ich brauchte. Deshalb musste ich ein paar kombinieren, um das richtige Ergebnis zu erzielen

um einfach Sonderzeichen zu entfernen und durch einen (.) Punkt zu ersetzen

for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done

zur verwendung in einem cronjob habe ich folgendes gemacht, um jede minute zu rennen

*/1 * * * * cd /path/to/files/ && for f in *.txt; do mv "$f" `echo $f | sed "s/[^a-zA-Z0-9.]/./g"`; done >/dev/null 2>&1

Ich hoffe, jemand findet dies hilfreich, da es meinen Tag gemacht hat :)

Topps70
quelle
(1) Aus Gründen der Übersichtlichkeit möchten Sie möglicherweise ändern `…`, $(…)um dies , dies und das anzuzeigen . (2) Sie sollten immer die Referenzen Ihrer Shell-Variablen angeben (z. B. "$f"), es sei denn, Sie haben einen guten Grund, dies nicht zu tun, und Sie sind sicher, dass Sie wissen, was Sie tun. Dies gilt auch für echo "$f" | sed …. Dies gilt auch für den gesamten $(…)(oder `…`) Ausdruck. dh mv "$f" "$(echo "$f" | sed "…")". … (Fortsetzung)
Scott
(Fortsetzung)… (3) Sie sollten sagen , um vor Dateinamen zu schützen, die mit beginnen . (4) Wenn Sie Dateien mit den Namen "foo ♥ bar.txt" und "foo ♠ bar.txt" haben, werden beide in "foo.bar.txt" umbenannt (versucht), was möglicherweise dazu führt, dass alle bis auf eine der Dateien gelöscht werden Dateien, die zerstört werden sollen. (5) Warum um alles in der Welt möchten Sie dies einmal pro Minute tun? mv -- "$f" …-
Scott
Ich habe ein Torrent-Skript, das Dateien automatisch herunterlädt. und manchmal enthalten einige Dateien Zeichen, die den Uploader abschrecken. Durch einfaches Umbenennen von Dateien mit Sonderzeichen behebt mein Cron alle meine Probleme und der Uploader erledigt seine Arbeit reibungslos.
Topps70
Also (diese Datei wurde heruntergeladen.ext) wird zu (diese Datei wurde heruntergeladen.ext)
Topps70
0

Wenn Sie nun wissen, welche Codierung für die Dateinamen auf der Remote-Seite verwendet wird ("latin1" - gemäß den Kommentaren zur ersten Antwort), können Sie auch den zweiten Weg gehen - führen Sie ein lokales Terminal aus und ssh in einem solchen Weise, dass die entfernten Dateinamen korrekt angezeigt werden (anstatt auf die erste Weise: Benennen Sie sie um) .

Wie ich könnten Sie ein Terminal lokal starten, das in dieser speziellen Codierung funktioniert, vielleicht so:

LC_ALL = de_DE.latin1 xvt &

xvt steht für Ihr Terminalprogramm.

Vielleicht wird das vorhandene Gebietsschema aufgerufen en_US.iso88591und nicht en_US.latin1, wie ich angenommen habe.

imz - Ivan Zakharyaschev
quelle
0

Dies entspricht nicht den Massenanforderungen, aber ich hatte gerade ein ähnliches Problem, als ich mehrere Versionen einer Datei mit ähnlichen Namen hatte, die sich nur durch ein seltsames Zeichen unterschieden. Leider bedeutete dies, dass ich die Täter mit dem von mir normalerweise verwendeten Wildcard-Trick nicht umbenennen konnte.

Am Ende habe ich mit Filezilla eine Verbindung als SFTP-Client hergestellt, die Dateien durchsucht und über die GUI umbenannt. Filezilla handhabte die zweifelhaften Zeichen recht gut.

kabadisha
quelle