Ich habe einen ziemlich großen Satz (~15 GB) Textdateien. Diese Dateien sind im Wesentlichen einfache Datenbanken, die Anmeldeinformationen enthalten, und die darin enthaltenen Anmeldeinformationen liegen oft außerhalb des 128-stelligen ASCII-Bereichs (Akzentzeichen und dergleichen).
Wenn ich versuche, einige dieser Dateien mit folgendem zu sortieren:
sort -u input.txt -o output.txt
... erhalte ich die folgende Fehlermeldung:
sort: string comparison failed: Invalid or incomplete multibyte or wide character
sort: Set LC_ALL='C' to work around the problem.
Ich habe viel darüber gelesen, wie die Verwendung von Befehlen, die mit Zeichen arbeiten, wie und , LC_ALL=C
beschleunigen kann , einschließlichsort
grep
Stephane Chazelas' brillante Antwortzu diesem Thema, aber ich mache mir insbesondere Sorgen über die Auswirkungen, die die Verwendung auf meinen Datensatz hat.
Ist es wahrscheinlich, dass beim Ausführen LC_ALL=C sort -u
dieser Dateien alle Nicht-ASCII-Zeichen entfernt werden?
Wenn es, was kann ich dann stattdessen tun, um alle "ungültige oder unvollständige Multibyte- oder Wide-Zeichen" aus diesen Dateien, sodass ich sie sortieren kann, ohne LC_ALL=C
? zu verwenden.
Antwort1
Ist es wahrscheinlich, dass durch das Ausführen von LC_ALL=C sort -u auf diesen Dateien alle Nicht-ASCII-Zeichen entfernt werden?
In diesem Fall nicht. Nein – sort
wir arbeiten direkt mit den Bytewerten, anstatt zu versuchen, sie in Zeichen umzuwandeln.
Das Gleiche gilt jedoch nicht unbedingt für andere Tools. Programme, die in C (der Sprache) geschrieben sind, verhalten sich am wahrscheinlichsten so. Programme, die in Sprachen mit starker Unterscheidung zwischen Byte und Zeichen geschrieben sind, wie etwa Python 3, sollten Eingaben, die nicht dem Zeichensatz entsprechen, grundsätzlich ablehnen. Und ich kann mir durchaus schlecht geschriebene Programme vorstellen, die die Fehler ignorieren und ?
stattdessen ein � oder a ausgeben.
Wenn ja, was kann ich stattdessen tun, um alle „ungültigen oder unvollständigen Multibyte- oder Breitzeichen“ aus diesen Dateien zu korrigieren/entfernen, sodass ich sie sortieren kann, ohne LC_ALL=C zu verwenden?
Stellen Sie sicher, dass alle die gleiche Dateikodierung verwenden (vorzugsweise UTF-8) und dass Ihr Gebietsschema die gleiche Kodierung verwendet. Der Fehler sollte bei einer gültigen UTF-8-Datei nie auftreten, egal wie groß sie ist.
Antwort2
Da ich meine Dateien letztendlich durch viele verschiedene Bash-Tools wie sort
, grep
, awk
, wc
und leiten musste tr
, entschied ich mich für die sicherere „richtige Lösung“, die in der akzeptierten Antwort angegeben war, nämlich sie alle zuerst in UTF-8 umzuwandeln. Das war letztendlich etwas schwieriger als erwartet, nicht zuletzt, weil ich eine Weile brauchte, um zu erkennen, dass file
nicht zuverlässig bestimmt werden kann, ob eine Datei ASCII oder UTF-8 ist (weil nicht die gesamte Datei überprüft wird), also stelle ich diese Antwort hier für die Nachwelt ein.
Um definitiv zu bestimmen, in welcher Kodierung Ihre Dateien vorliegen, stellen Sie zunächst sicher, dass das uchardet
Paket über den Cygwin-Installer installiert wurde oderapt-cyg, dann renne:
uchardet *.txt
Oder wenn Sie Cygwin nicht verwenden:
chardet *.txt
chardet
Verschieben Sie alle aufgelisteten Dateien ASCII
in einen eigenen Ordner und führen Sie for
in diesem Ordner die folgende Schleife aus:
for i in *.txt; do iconv -f ASCII -t UTF-8 "$i" >> "${i%.txt}_utf.txt"; done;
Es durchläuft alle .txt
Dateien in einem Ordner und erstellt davon UTF-8-Versionen mit utf
hinzugefügtem Suffix.
Beim erneuten Ausführen uchardet *.txt
werden möglicherweise immer noch einige Dateien als angezeigt ASCII
. Dies liegt daran, dass ASCII eine Teilmenge von UTF-8 ist undbedeutet einfachdass diese Dateien keine Zeichen außerhalb des 128-Bit-ASCII-Bereichs enthalten.
Jetzt sollten Sie in der Lage sein, auszuführen, sort
ohne verwenden zu müssen LC_ALL=C
.