Verwenden Sie awk, um die Byte-Reihenfolge zu entfernen

105

Wie würde ein awkSkript (vermutlich ein Einzeiler) zum Entfernen einer Stückliste aussehen?

Spezifikation:

  • drucke jede Zeile nach der ersten ( NR > 1)
  • für die erste Zeile: Wenn es mit #FE #FFoder beginnt #FF #FE, entfernen Sie diese und drucken Sie den Rest
Boldewyn
quelle

Antworten:

114

Versuche dies:

awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}{print}' INFILE > OUTFILE

Entfernen Sie im ersten Datensatz (Zeile) die Stücklistenzeichen. Drucken Sie jeden Datensatz.

Oder etwas kürzer, wenn Sie wissen, dass die Standardaktion in awk darin besteht, den Datensatz zu drucken:

awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1' INFILE > OUTFILE

1 ist die kürzeste Bedingung, die immer als wahr ausgewertet wird, sodass jeder Datensatz gedruckt wird.

Genießen!

- ADDENDUM -

Die häufig gestellten Fragen zu Unicode Byte Order Mark (BOM) enthalten die folgende Tabelle mit den genauen Stücklistenbytes für jede Codierung:

Bytes         |  Encoding Form
--------------------------------------
00 00 FE FF   |  UTF-32, big-endian
FF FE 00 00   |  UTF-32, little-endian
FE FF         |  UTF-16, big-endian
FF FE         |  UTF-16, little-endian
EF BB BF      |  UTF-8

So können Sie aus der obigen Tabelle sehen, wie Stücklistenbytes \xef\xbb\xbfentsprechen EF BB BF UTF-8.

Bartosz
quelle
1
Es scheint, dass der Punkt in der Mitte der Unteranweisung zu viel ist (zumindest beschwert sich mein awk darüber). Abgesehen davon ist es genau das, wonach ich gesucht habe, danke!
Boldewyn
5
Diese Lösung funktioniert jedoch nur für UTF-8-codierte Dateien. Für andere, wie UTF-16, siehe Wikipedia für die entsprechende Stücklistendarstellung: en.wikipedia.org/wiki/Byte_order_mark
Boldewyn
2
Also: awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILEund stellen Sie sicher, dass INFILE und OUTFILE unterschiedlich sind!
Steve Clay
1
Wenn Sie verwendet haben, können perl -i.orig -pe 's/^\x{FFFE}//' badfileSie sich bei der Codierung auf Ihre Variablen PERL_UNICODE und / oder PERLIO verlassen. PERL_UNICODE = SD würde für UTF-8 funktionieren; für die anderen brauchst du PERLIO.
Tchrist
1
Vielleicht etwas kürzere Version:awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1'
TrueY
122

Verwenden von GNU sed(unter Linux oder Cygwin):

# Removing BOM from all text files in current directory:
sed -i '1 s/^\xef\xbb\xbf//' *.txt

Auf FreeBSD:

sed -i .bak '1 s/^\xef\xbb\xbf//' *.txt

Vorteil der Verwendung von GNU oder FreeBSD sed: Der -iParameter bedeutet "an Ort und Stelle" und aktualisiert Dateien, ohne dass Umleitungen oder seltsame Tricks erforderlich sind.

Auf dem Mac:

Diese awkLösung in einer anderen Antwort funktioniert , aber der sedobige Befehl funktioniert nicht. Zumindest in der Mac (Sierra) sed-Dokumentation wird nicht erwähnt, dass hexadezimales Escape-Ala unterstützt wird \xef.

Ein ähnlicher Trick kann mit jedem Programm erreicht werden, indem spongevon moreutils zum Werkzeug geleitet wird :

awk '…' INFILE | sponge INFILE
Denilson Sá Maia
quelle
5
Ich habe den zweiten Befehl genau unter Mac OS X ausprobiert und das Ergebnis war "Erfolg", aber die Ersetzung fand nicht statt.
Trejkaz
1
Es ist erwähnenswert, dass diese Befehle eine bestimmte Bytesequenz ersetzen, die eine der möglichen Bytereihenfolgenmarkierungen ist . Möglicherweise hatte Ihre Datei eine andere Stücklistenfolge. (Ich kann nicht anders als das, da ich keinen Mac habe)
Denilson Sá Maia
3
Als ich den zweiten Befehl unter OS X für eine Datei versuchte, die 0xef 0xbb 0xbf als Stückliste verwendete, wurde die Ersetzung nicht durchgeführt.
John Wiseman
In OSX konnte ich dies nur über Perl zum Laufen bringen
Ian
Unter OS X El Capitan 10.11.6funktioniert dies nicht, aber die offizielle Antwort stackoverflow.com/a/1068700/9636 funktioniert einwandfrei .
Heath Borders
42

Nicht awk, aber einfacher:

tail -c +4 UTF8 > UTF8.nobom

So überprüfen Sie die Stückliste:

hd -n 3 UTF8

Wenn Stückliste vorhanden ist, sehen Sie: 00000000 ef bb bf ...

Steve Clay
quelle
6
Stücklisten sind 2 Bytes für UTF-16 und 4 Bytes für UTF-32 und haben natürlich überhaupt kein Geschäft mit UTF-8.
Tchrist
2
@ KarolyHorvath Ja genau. Die Verwendung wird nicht empfohlen. Es bricht Sachen. Die Codierung sollte durch ein übergeordnetes Protokoll festgelegt werden.
Tchrist
1
@tchrist: du meinst es bricht kaputtes Zeug? :) Richtige Apps sollten mit dieser Stückliste umgehen können.
Karoly Horvath
7
@ KarolyHorvath Ich meine, es bricht viele Programme . Habe ich das nicht gesagt? Wenn Sie einen Stream in den UTF-16- oder UTF-32-Codierungen öffnen, weiß der Decoder, dass die Stückliste nicht gezählt wird. Wenn Sie UTF-8 verwenden, präsentieren Decoder die Stückliste als Daten. Dies ist ein Syntaxfehler in unzähligen Programmen. Sogar Javas Decoder verhält sich so, BY DESIGN! Stücklisten in UTF-8-Dateien sind falsch platziert und ein Ärgernis: Sie sind ein Fehler! Sie brechen viele Dinge. Auch nur cat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8wird gebrochen. Verwenden Sie niemals eine Stückliste für UTF-8. Zeitraum.
Tchrist
6
hdist unter OS X (ab 10.8.2) nicht verfügbar. Um dort nach einer UTF-8-Stückliste zu suchen, können Sie Folgendes verwenden : head -c 3 file | od -t x1.
mklement0
21

Zusätzlich zum Konvertieren von CRLF-Zeilenenden in LF werden dos2unixauch Stücklisten entfernt:

dos2unix *.txt

dos2unix konvertiert auch UTF-16-Dateien mit einer Stückliste (jedoch nicht UTF-16-Dateien ohne Stückliste) in UTF-8 ohne Stückliste:

$ printf '\ufeffä\n'|iconv -f utf-8 -t utf-16be>bom-utf16be
$ printf '\ufeffä\n'|iconv -f utf-8 -t utf-16le>bom-utf16le
$ printf '\ufeffä\n'>bom-utf8
$ printf 'ä\n'|iconv -f utf-8 -t utf-16be>utf16be
$ printf 'ä\n'|iconv -f utf-8 -t utf-16le>utf16le
$ printf 'ä\n'>utf8
$ for f in *;do printf '%11s %s\n' $f $(xxd -p $f);done
bom-utf16be feff00e4000a
bom-utf16le fffee4000a00
   bom-utf8 efbbbfc3a40a
    utf16be 00e4000a
    utf16le e4000a00
       utf8 c3a40a
$ dos2unix -q *
$ for f in *;do printf '%11s %s\n' $f $(xxd -p $f);done
bom-utf16be c3a40a
bom-utf16le c3a40a
   bom-utf8 c3a40a
    utf16be 00e4000a
    utf16le e4000a00
       utf8 c3a40a
Lri
quelle
3

Ich weiß, dass die Frage an Unix / Linux gerichtet war, dachte, es wäre wert, eine gute Option für Unix-herausgeforderte (unter Windows, mit einer Benutzeroberfläche) zu erwähnen.
Bei einem WordPress-Projekt stieß ich auf dasselbe Problem (die Stückliste verursachte Probleme mit dem RSS-Feed und der Seitenüberprüfung) und musste alle Dateien in einem ziemlich großen Verzeichnisbaum untersuchen, um die Datei mit der Stückliste zu finden. Es wurde eine Anwendung namens Replace Pioneer gefunden und darin:

Batch Runner -> Suchen (um alle Dateien in den Unterordnern zu finden) -> Vorlage ersetzen -> Binär Stückliste entfernen (hierfür gibt es eine vorgefertigte Vorlage zum Suchen und Ersetzen).

Es war nicht die eleganteste Lösung und erforderte die Installation eines Programms, was ein Nachteil ist. Aber als ich herausfand, was um mich herum vorging, funktionierte es wie ein Zauber (und ich fand 3 Dateien von ungefähr 2300, die mit Stückliste waren).

Arnon Zamir
quelle
1
Ich bin so glücklich, als ich Ihre Lösung gefunden habe, aber ich habe nicht das Privileg, Software auf dem Firmencomputer zu installieren. Hat heute viel Zeit in Anspruch genommen, bis ich die Alternative herausgefunden habe: Verwenden von Notepad ++ mit PythonScript-Plugin. superuser.com/questions/418515/… Trotzdem danke!
Hoàng Long