Entfernen aller Nicht-ASCII-Zeichen aus einem Workflow (Datei)

12

Wie entferne ich alle Nicht-ASCII-Zeichen aus einer Datei? Würde es einen bestimmten Befehl geben, um dies auszuführen?

grep --colour='auto' -P -n'[^\x00-\x7]' /usr/local/...

Ich glaube, dies findet die Zeichen innerhalb des Workflows, aber wie würde ich alle Instanzen der fraglichen Zeichen entfernen?

Mizole Ni
quelle
2
verwandt: Wenn Sie nur Probleme mit Steuerzeichen vermeiden möchten (anstatt sie stillschweigend loszuwerden), können Sie sie einfach cat -vin ASCII-Repräsentation für sie anzeigen. ( ^G\007
ZB
1
Wenn Sie "Nicht-ASCII-Zeichen" sagen, schließen Sie auch Zeichen mit Akzent ein?
Captain Man
1
@MatijaNalis Weitere Informationen zur Darstellung: en.wikipedia.org/wiki/Caret_notation
wjandrea
1
Was ist der Anwendungsfall? Sehr oft gibt es spezielle Tools oder unterschiedliche Ansätze, die viel besser funktionieren, als nur eine Reihe von Sonderzeichen zu entfernen. Bitte beachten Sie, dass ASCII mehrere "Sonderzeichen" wie vertikale Tabulatoren, Glocken und NUL enthält - sind Sie sicher, dass Sie keine druckbaren Zeichen meinen ?
l0b0

Antworten:

25

ASCII-Zeichen sind Zeichen im Bereich von 0 bis einschließlich 177 (oktal) .

Verwenden Sie, um Zeichen außerhalb dieses Bereichs in einer Datei zu löschen

LC_ALL=C tr -dc '\0-\177' <file >newfile

Der trBefehl ist ein Dienstprogramm, das einzelne Zeichen bearbeitet , entweder durch andere einzelne Zeichen ersetzt (Transliteration), löscht oder Läufe desselben Zeichens zu einem einzelnen Zeichen komprimiert.

Der obige Befehl würde fileden geänderten Inhalt lesen und in ihn schreiben newfile. Mit dieser -dOption trlöscht das Dienstprogramm Zeichen (anstatt sie zu transliterieren) und -cberücksichtigt Zeichen außerhalb des angegebenen Intervalls (statt innerhalb).

LC_ALL=Cstellt sicher, dass jeder Byte-Wert ein gültiges Zeichen bildet. Ohne diese trOption würden einige Implementierungen abgebrochen, wenn Bytefolgen gefunden würden, die in der Zeichencodierung des Gebietsschemas keine gültigen Zeichen bilden.


Verwenden Sie, um die Originaldatei durch die geänderte zu ersetzen

LC_ALL=C tr -dc '\0-\177' <file >newfile &&
mv newfile file

Dadurch wird die neue Datei nach erfolgreichem Abschluss in den Namen der alten Datei umbenannt tr. Wird der trVorgang nicht erfolgreich abgeschlossen, da die ursprüngliche Datei nicht gelesen oder nicht in die neue Datei geschrieben werden konnte, bleibt die ursprüngliche Datei unverändert.

Um die Metadaten (Berechtigungen usw.) der Originaldatei so weit wie möglich zu erhalten, verwenden Sie alternativ

cp file tmpfile &&
LC_ALL=C tr -dc '\0-\177' <tmpfile >file &&
rm tmpfile
Kusalananda
quelle
14

Mit perl

perl -pi -e 's/[^[:ascii:]]//g'
Isaac
quelle
9

Wenn Sie nur einen regulären Ausdruck benötigen [\x00-\x7F], den Sie auf mehrere Dienstprogramme anwenden können:

<file LC_ALL=C   sed   's/[^\o0-\o177]//g'      # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\177]/,"");print}'
<file            perl  -pe 's/[^[:ascii:]]//g;'
<file LC_ALL=C   tr    -dc '\0-\177'

Verstehen Sie, dass sed, awk und perl "Textdateien" wie in Unix definiert erwarten. In diesem Fall funktionieren alle gut. Insbesondere fügt awk jedoch eine nachgestellte neue Zeile hinzu (unabhängig davon, ob diese in der Quelldatei vorhanden war oder nicht) (mit printf werden ALLE neuen Zeilen in der Eingabe entfernt). Das tr kann mit jedem Dateityp verwendet werden. Das NUL ( \0) ist jedoch kein gültiges Zeichen in einer POSIX-Textdatei und sollte vermieden werden:

Die Zeilen enthalten keine NUL-Zeichen ...

Tatsächlich würden viele Steuerzeichen unter bestimmten Bedingungen andere Probleme verursachen.
Also, wahrscheinlich brauchst du[\x07-\x0d\x20-\x7e]

<file LC_ALL=C   sed   's/[^\o007-\o015\o040-\o176]//g'            # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\15\40-\176]/,"");print}'
<file            perl  -pe 's/[^\x{7}-\x{d}\x{20}-\x{7e}]//g;'
<file LC_ALL=C   tr    -dc '\7-\15\40-\176'

Der Bereich 7-13 (in Dezimal) ist \a\b\t\n\v\f\r(in Reihenfolge).
Ein ähnlicher (wahrscheinlich portablerer) Bereich könnte als [^[:space:][:print:]] (similar because it doesn't include\ a \ b` (Glocke und Rücktaste) geschrieben werden.

<file LC_ALL=C   sed   's/[^[:space:][:print:]]//g'  # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^[:space:][:print:]]/,"");print}'
<file            perl   -pe 's/[^[:space:][:print:]]//g;'
<file LC_ALL=C   tr     -dc '[:space:][:print:]'

Verwandte:
Regex jedes ASCII-Zeichen
Perl-Lösung
Posix-Textdatei

Isaac
quelle
Beachten Sie, dass die Eingabe für treinen beliebigen Dateityp erfolgen kann, nicht nur für Textdateien. awkAuf der anderen Seite nimmt eine Textdatei.
Kusalananda
Es ist ziemlich schwer für mich, irgendetwas anderes zu finden, um eine Datei "nur ASCII-Zeichen" als eine "Textdatei" zu bezeichnen (ja, ja: in Laienbegriffen). @ Kusalananda (Anmerkung zu awk trotzdem hinzugefügt).
Isaac
Beachten Sie, dass dies gensub()eine Gawk-Erweiterung ist. Sie möchten gsub(...); print, und verwenden Sie Oktal anstelle von Hex-Sequenzen (und LC_ALL = C), um (mehr) portabel zu sein.
Stéphane Chazelas
@ StéphaneChazelas Was ist die Einschränkung von GNU sed, die die Syntax GNU-spezifisch macht (ich verstehe das POSIXLY_CORRECT-Problem).
Isaac
[^\o0]soll in POSIX mit anderen Zeichen als Backslash, o und 0 übereinstimmen sed(in allen Implementierungen außer GNU sed). Dies ist keine Einschränkung von GNU, sedsondern eine nicht konforme Erweiterung, weshalb sie deaktiviert ist, wenn sich POSIXLY_CORRECT in der Umgebung befindet.
Stéphane Chazelas