Ich muss einige nicht druckbare Zeichen durch Leerzeichen in der Datei ersetzen.
Genauer gesagt, werden alle Zeichen von 0x00
bis zu 0x1F
, mit der Ausnahme 0x09
(TAB), 0x0A
(neue Zeile), 0x0D
(CR)
Bis jetzt musste ich nur den 0x00
Charakter ersetzen . Da mein vorheriges Betriebssystem AIX war (ohne GNU-Befehle), kann ich es nicht verwenden sed
(nun, ich kann, aber es hatte einige Einschränkungen). Also fand ich den nächsten Befehl mit perl
, der wie erwartet funktionierte:
perl -p -e 's/\x0/ /g' $FILE_IN > $FILE_OUT
Jetzt arbeite ich unter Linux und habe erwartet, dass ich den sed
Befehl verwenden kann.
Meine Fragen:
Ist dieser Befehl geeignet, um diese Zeichen zu ersetzen? Ich habe es versucht und es scheint zu funktionieren, aber ich möchte sichergehen:
perl -p -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Ich dachte
perl -p
funktioniert wiesed
. Warum funktioniert der vorherige Befehl (zumindest schlägt er nicht fehl) und der nächste nicht?sed -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Es sagt mir:
sed: -e Ausdruck # 1, char 34: Ungültiges Kollatierungszeichen
perl -p
druckt das Endprodukt aus,stdin
nachdem Sie die gewünschten Vorgänge ausgeführt haben. In diesem Fall handelt es sich nur um einen Ersatz.sed
Der reguläre Ausdruck könnte anders sein alsperl
.Antworten:
Das ist ein typischer Job für
tr
:In Ihrem Fall funktioniert dies nicht,
sed
da Sie sich in einem Gebietsschema befinden, in dem diese Bereiche keinen Sinn ergeben. Wenn Sie die Arbeit mit Byte - Werten wollen wie auf Zeichen entgegengesetzt und in dem die Reihenfolge auf dem numerischen Wert dieses Bytes basiert, ist Ihre beste Wette ist , um das C - Gebietsschema zu verwenden . Ihr Code hätteLC_ALL=C
mit GNU funktioniertsed
, aber die Verwendungsed
(geschweige dennperl
) ist hier etwas übertrieben (und diese\xXX
sind nichtsed
implementierungsübergreifend portierbar , während diesertr
Ansatz POSIX ist).Sie können auch der Vorstellung Ihres Gebietsschemas vertrauen, welche druckbaren Zeichen enthalten sind:
Mit GNU
tr
(wie es normalerweise auf Linux-basierten Systemen zu finden ist) funktioniert dies jedoch nur in Gebietsschemas, in denen Zeichen Einzelbyte sind (also normalerweise nicht UTF-8).Im C-Gebietsschema würde dies auch DEL (0x7f) und alle obigen Bytewerte ausschließen (nicht in ASCII).
In UTF-8-Gebietsschemas können Sie GNU verwenden,
sed
das nicht das Problemtr
hat, das GNU hat:(beachten Sie, dass diejenigen
\r
,\t
sind nicht Standard, und GNUsed
wird sie nicht erkennen , wennPOSIXLY_CORRECT
in der Umgebung ist (wird sie als Backslash behandeln, r und t Teil des Satzes ist , wie POSIX erfordert)).Es werden jedoch keine Bytes konvertiert, die keine gültigen Zeichen bilden.
quelle
tr
Befehl tut. Ich verstehe (mehr oder weniger) wasLC_ALL = C
ist, aber nicht alle zusammen.tr -d
Entfernt trotzdem diese Zeichen, aber ich möchte durch Leerzeichen ersetzen. Entschuldigung, der Titel war falsch. Ich habe gerade gemerkt, als @don_crissti modifiziert wurde.XCOM
. Zum Beispiel werden Nicht-ASCII-Zeichen wieÉ
kodifiziert (mitod -xa
) als0xC9
, also denke ich, wäre esISO-8859-1
.locale -a
, um festzustellen, ob auf Ihrem System Gebietsschemas mit iso8859-1 als Zeichensatz vorhanden sind, undLC_CTYPE=<that-locale> tr ...[:print:]...
um nicht druckbare Dateien in diesem Gebietsschema zu konvertieren. Oder Sie können iconv verwenden, um diese Dateien in den Zeichensatz Ihres Gebietsschemas zu konvertieren.LC_ALL=en_US.iso88591
. Ihr Befehl (tr -c '[:print:]\t\r\n' '[ *]'
) funktioniert also einwandfrei, ohne das Gebietsschema zu ändern oder die Datei zu konvertieren. Vielen Dank.Ich habe versucht, eine Benachrichtigung über libnotify mit Inhalten zu senden, die möglicherweise nicht druckbare Zeichen enthalten. Die vorhandenen Lösungen haben bei mir nicht ganz funktioniert (Verwenden einer Whitelist von Zeichen mit
tr
Werken, Entfernen aller Multi-Byte-Zeichen).Folgendes hat beim Bestehen des 💩-Tests funktioniert:
quelle