Ich versuche, eine Zeichenfolge in einem Makefile unter Mac OS X für das Cross-Compilieren auf iOS zu ersetzen. Die Zeichenfolge enthält doppelte Anführungszeichen. Der Befehl lautet:
sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
Und der Fehler ist:
sed: RE error: illegal byte sequence
Ich habe versucht, den doppelten Anführungszeichen, Kommas, Bindestrichen und Doppelpunkten ohne Freude zu entkommen. Beispielsweise:
sed -i "" 's|\"iphoneos-cross\"\,\"llvm-gcc\:\-O3|\"iphoneos-cross\"\,\"clang\:\-Os|g' Configure
Ich habe verdammt viel Zeit damit, das Problem zu beheben. Weiß jemand, wie man sed
die Position der illegalen Byte-Sequenz druckt? Oder weiß jemand, was die illegale Bytesequenz ist?
LC_CTYPE=C && LANG=C && sed command
LANG
Ding.sed
(wie auch unter OS X verwendet) erfordert-i ''
(separates Optionsargument mit leeren Zeichenfolgen) für die direkte Aktualisierung ohne Sicherungsdatei. mit GNU funktioniertsed
nur-i
von selbst - siehe stackoverflow.com/a/40777793/45375Antworten:
Ein Beispielbefehl mit dem folgenden Symptom
sed 's/./@/' <<<$'\xfc'
schlägt fehl, da das Byte0xfc
kein gültiges UTF-8-Zeichen ist.Beachten Sie, dass GNU
sed
(Linux, aber auch unter macOS installierbar) das ungültige Byte einfach weiterleitet, ohne einen Fehler zu melden.Die Verwendung der zuvor akzeptierten Antwort ist eine Option, wenn es Ihnen nichts ausmacht, die Unterstützung für Ihr wahres Gebietsschema zu verlieren (wenn Sie sich in einem US-System befinden und nie mit fremden Zeichen umgehen müssen, kann dies in Ordnung sein.)
Doch das kann die gleiche Wirkung werden mußte Ad-hoc für einen einzigen Befehl nur :
Hinweis: Was zählt, ist eine effektive
LC_CTYPE
Einstellung vonC
,LC_CTYPE=C sed ...
die normalerweise auch funktioniert. WennLC_ALL
sie jedoch (auf etwas anderes alsC
) eingestellt wird, werden einzelneLC_*
Variablen der Kategorie wie zLC_CTYPE
. Der robusteste Ansatz ist daher das FestlegenLC_ALL
.Die (effektive) Einstellung
LC_CTYPE
,C
Zeichenfolgen so zu behandeln, als ob jedes Byte ein eigenes Zeichen wäre (es wird keine Interpretation basierend auf Codierungsregeln durchgeführt), ohne Berücksichtigung der UTF-8-Codierung (Multibyte-on-Demand) , die OS X standardmäßig verwendet , wo fremde Zeichen haben Multibyte - Codierungen .Kurz gesagt: Die Einstellung
LC_CTYPE
aufC
bewirkt , dass die Shell und die Dienstprogramme nur grundlegende englische Buchstaben als Buchstaben erkennen (diejenigen im 7-Bit-ASCII-Bereich), sodass fremde Zeichen entstehen. werden nicht als Buchstaben behandelt , was beispielsweise dazu führt, dass Konvertierungen in Groß- / Kleinbuchstaben fehlschlagen.Auch dies kann in Ordnung sein, wenn Sie nicht mit Multibyte-codierten Zeichen wie übereinstimmen
é
müssen und diese Zeichen einfach weitergeben möchten .Wenn dies nicht ausreicht und / oder Sie die Ursache des ursprünglichen Fehlers verstehen möchten (einschließlich der Ermittlung, welche Eingabebytes das Problem verursacht haben) und bei Bedarf Codierungskonvertierungen durchführen möchten , lesen Sie weiter unten.
Das Problem ist, dass die Codierung der Eingabedatei nicht mit der der Shell übereinstimmt.
Genauer gesagt, enthält die Eingabedatei in einer Weise codierten Zeichen , die nicht gültig in UTF-8 (als @Klas Lindbäck in einem Kommentar angegeben) - das ist , was die
sed
Fehlermeldung von zu sagen versuchtinvalid byte sequence
.Höchstwahrscheinlich verwendet Ihre Eingabedatei eine Einzelbyte-8-Bit-Codierung, wie sie
ISO-8859-1
häufig zum Codieren von "westeuropäischen" Sprachen verwendet wird.Beispiel:
Der akzentuierte Buchstabe
à
hat den Unicode-Codepunkt0xE0
(224) - der gleiche wie inISO-8859-1
. Aufgrund der Art der UTF-8- Codierung wird dieser einzelne Codepunkt jedoch als 2 Byte dargestellt0xC3 0xA0
, während der Versuch, das einzelne Byte zu übergeben, unter UTF-8 ungültig0xE0
ist .Hier ist eine Demonstration des Problems unter Verwendung der Zeichenfolge
voilà
, die als codiert istISO-8859-1
, wobei die Zeichenfolgeà
als ein Byte dargestellt wird (über eine in ANSI-C zitierte Bash-Zeichenfolge ($'...'
), mit\x{e0}
der das Byte erstellt wird):Beachten Sie, dass der
sed
Befehl praktisch ein No-Op ist, der die Eingabe einfach weiterleitet, aber wir brauchen ihn, um den Fehler zu provozieren:Um das Problem einfach zu ignorieren , kann der obige
LCTYPE=C
Ansatz verwendet werden:Wenn Sie feststellen möchten, welche Teile der Eingabe das Problem verursachen , versuchen Sie Folgendes:
Die Ausgabe zeigt Ihnen alle Bytes, für die das High-Bit gesetzt ist (Bytes, die den 7-Bit-ASCII-Bereich überschreiten), in hexadezimaler Form. (Beachten Sie jedoch, dass dies auch korrekt codierte UTF-8-Multibyte-Sequenzen umfasst - ein komplexerer Ansatz wäre erforderlich, um In-UTF-8-Bytes spezifisch ungültig zu identifizieren.)
Codierungskonvertierungen bei Bedarf durchführen :
Das Standarddienstprogramm
iconv
kann zum Konvertieren in (-t
) und / oder von (-f
) -Codierungen verwendet werden.iconv -l
listet alle unterstützten auf.Beispiele:
Konvertieren Sie FROM
ISO-8859-1
in die in der Shell gültige Codierung (basierend aufLC_CTYPE
, dieUTF-8
standardmäßig basiert ), basierend auf dem obigen Beispiel:Beachten Sie, dass Sie mit dieser Konvertierung Fremdzeichen richtig abgleichen können :
Um die Eingabe
ISO-8859-1
nach der Verarbeitung wieder in umzuwandeln, leiten Sie das Ergebnis einfach an einen andereniconv
Befehl weiter:quelle
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
drucktsed: RE error: illegal byte sequence
für mich auf Sierra.echo $LC_ALL
gibten_US.UTF-8
FWIW aus.LC_ALL
überschreibtLC_*
, einschließlichLC_CTYPE
, wie in der Antwort erläutert.Fügen Sie die folgenden Zeilen zu Ihren
~/.bash_profile
oder Ihren~/.zshrc
Dateien hinzu.quelle
LC_CTYPE
,C
dass jedes Byte in Zeichenfolgen ein eigenes Zeichen ist, ohne dass Codierungsregeln angewendet werden. Da ein Verstoß gegen (UTF-8) -Codierungsregeln das ursprüngliche Problem verursacht hat, verschwindet das Problem. Der Preis, den Sie zahlen, ist jedoch, dass die Shell und die Dienstprogramme dann nur die grundlegenden englischen Buchstaben (die im 7-Bit-ASCII-Bereich) als Buchstaben erkennen. Siehe meine Antwort für mehr.LC_CTYPE=C sed …
, dh nur auf den Befehl sed.Meine Problemumgehung war die Verwendung von Perl:
quelle
Die Antwort von mklement0 ist großartig, aber ich habe einige kleine Verbesserungen.
Es scheint eine gute Idee zu sein,
bash
die Codierung bei der Verwendung explizit anzugebeniconv
. Außerdem sollten wir ein Zeichen für die Bytereihenfolge voranstellen ( obwohl der Unicode-Standard dies nicht empfiehlt ), da es zu legitimen Verwechslungen zwischen UTF-8 und ASCII ohne ein Zeichen für die Bytereihenfolge kommen kann . Leider wirdiconv
keine Bytereihenfolge vorangestellt, wenn Sie explizit eine Endianness (UTF-16BE
oderUTF-16LE
) angeben. Daher müssen wir diese verwendenUTF-16
, die plattformspezifische Endianness verwendet, und dann verwendenfile --mime-encoding
, um die tatsächlich verwendete Endianness zu ermittelniconv
.(Ich schreibe alle meine Codierungen in Großbuchstaben, denn wenn Sie alle
iconv
unterstützten Codierungeniconv -l
auflisten, sind sie alle in Großbuchstaben.)quelle
file -b --mime-encoding
zum Erkennen und Melden der Codierung einer Datei. Es gibt jedoch einige Aspekte, die es wert sind, angesprochen zu werden, was ich in separaten Kommentaren tun werde.LC_CTYPE
ist normalerweise<lang_region>.UTF-8
, daher wird jede Datei ohne Stückliste (Byte-Order-Markierung) daher als UTF-8-Datei interpretiert. Nur in der Windows- Welt wird die Pseudo-Stückliste0xef 0xbb 0xff
verwendet. definitions UTF-8 nicht brauchen eine Stückliste und wird nicht empfohlen (wie Sie Zustand); Außerhalb der Windows-Welt führt diese Pseudo-Stückliste dazu, dass Dinge kaputt gehen .Unfortunately, iconv doesn't prepend a byte-order mark when you explicitly specify an endianness (UTF-16BE or UTF-16LE)
: Das ist beabsichtigt: Wenn Sie die Endianness explizit angeben , müssen Sie sie nicht auch über eine Stückliste wiedergeben, sodass keine hinzugefügt wird.LC_*
/LANG
Variablen:bash
,ksh
, undzsh
(möglicherweise andere, aber nichtdash
) tun , um die Zeichenkodierung respektieren; Überprüfen Sie in POSIX-ähnlichen Shells mit einem UTF-8-basierten Gebietsschema Folgendesv='ä'; echo "${#v}"
: Eine UTF-8-fähige Shell sollte einen Bericht erstellen1
. dh es sollte die Mehrbyte-Sequenzä
(0xc3 0xa4
) als einzelnes Zeichen erkennen. Vielleicht noch wichtiger ist jedoch: Die Standard - Utilities (sed
,awk
,cut
, ...) auch locale / Codierung bewusst sein müssen, und während die meisten von ihnen auf modernen Unix-Plattformen sind, gibt es Ausnahmen, wieawk
auf OSX, undcut
unter Linux.file
die UTF-8-Pseudo-Stückliste erkannt wird, aber das Problem ist, dass die meisten Unix-Dienstprogramme, die Dateien verarbeiten, dies nicht tun und sich normalerweise brechen oder zumindest schlecht verhalten, wenn sie mit einer konfrontiert werden.file
Identifiziert ohne Stückliste eine 7-Bit-Byte-Datei korrekt als ASCII und eine Datei mit gültigen UTF-8-Mehrbyte-Zeichen als UTF-8. Das Schöne an UTF-8 ist, dass es eine Obermenge von ASCII ist: Jede gültige ASCII-Datei ist per Definition eine gültige UTF-8-Datei (aber nicht umgekehrt); Es ist vollkommen zu sicher, eine ASCII-Datei als UTF-8 zu behandeln (was technisch gesehen einfach keineSie müssen lediglich einen iconv- Befehl vor dem sed- Befehl weiterleiten . Ex mit file.txt Eingabe:
Die Option -f ist der Codesatz 'von' und die Option -t ist die Konvertierung des Codesatzes 'nach'.
Achten Sie auf Groß- und Kleinschreibung. Webseiten zeigen normalerweise Kleinbuchstaben wie <charset = iso-8859-1 "/> und iconv verwendet Großbuchstaben. Sie haben eine Liste der von iconv unterstützten Codesätze in Ihrem System mit dem Befehl iconv -l
UTF8-MAC ist ein moderner OS Mac-Codesatz für die Konvertierung.
quelle
Ich habe einen Teil des Weges zur Beantwortung der oben genannten Fragen mit tr .
Ich habe eine CSV-Datei, bei der es sich um eine Kreditkartenabrechnung handelt, und ich versuche, sie in Gnucash zu importieren. Ich bin in der Schweiz ansässig und muss mich mit Worten wie Zürich auseinandersetzen. Bei dem Verdacht, dass Gnucash in numerischen Feldern nicht "" mag, entscheide ich mich, einfach alle zu ersetzen
mit
Hier geht:
Ich habe od verwendet , um etwas Licht ins Dunkel zu bringen: Beachten Sie den 374 auf halber Höhe dieses od-c- Ausgangs
Dann dachte ich, ich könnte versuchen, tr davon zu überzeugen , den richtigen Bytecode durch 374 zu ersetzen. Also habe ich zuerst etwas Einfaches ausprobiert, das nicht funktioniert hat, aber den Nebeneffekt hatte, mir zu zeigen, wo das störende Byte war:
Sie können tr- Kautionen am 374-Zeichen sehen.
Die Verwendung von Perl scheint dieses Problem zu vermeiden
quelle
Meine Problemumgehung hatte Gnu verwendet
sed
. Hat für meine Zwecke gut funktioniert.quelle
sed
eine Option, wenn Sie ungültige Bytes im Eingabestream ignorieren möchten (keineLC_ALL=C sed ...
Problemumgehung erforderlich ), da GNUsed
einfach ungültige Bytes weiterleitet, anstatt einen Fehler zu melden. Beachten Sie dies jedoch, wenn Sie alle ordnungsgemäß erkennen und verarbeiten möchten Bei Zeichen in der Eingabezeichenfolge führt kein Weg daran vorbei, zuerst die Codierung der Eingabe zu ändern (normalerweise miticonv
).