Utilizzo di awk per rimuovere il contrassegno di ordine byte


105

Come apparirebbe uno awkscript (presumibilmente un one-liner) per la rimozione di una distinta materiali ?

Specifica:

  • stampa ogni riga dopo la prima ( NR > 1)
  • per la prima riga: se inizia con #FE #FFo #FF #FE, rimuovili e stampa il resto

Risposte:


114

Prova questo:

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

Nel primo record (riga), rimuovere i caratteri BOM. Stampa ogni record.

O leggermente più breve, utilizzando la consapevolezza che l'azione predefinita in awk è stampare il record:

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

1 è la condizione più breve che restituisce sempre true, quindi ogni record viene stampato.

Godere!

- ADDENDUM -

Le domande frequenti su Unicode Byte Order Mark (BOM) includono la seguente tabella che elenca i byte BOM esatti per ciascuna codifica:

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

Quindi, puoi vedere come \xef\xbb\xbfcorrisponde ai EF BB BF UTF-8byte BOM dalla tabella sopra.


1
Sembra che il punto nel mezzo dell'istruzione sub sia troppo (almeno, il mio awk se ne lamenta). Oltre a questo è esattamente quello che ho cercato, grazie!
Boldewyn

5
Questa soluzione, tuttavia, funziona solo per i file con codifica UTF-8. Per altri, come UTF-16, vedere Wikipedia per la rappresentazione BOM corrispondente: en.wikipedia.org/wiki/Byte_order_mark
Boldewyn

2
Quindi: awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILEe assicurati che INFILE e OUTFILE siano diversi!
Steve Clay il

1
Se lo perl -i.orig -pe 's/^\x{FFFE}//' badfileusassi, potresti fare affidamento sulle tue invariabili PERL_UNICODE e / o PERLIO per la codifica. PERL_UNICODE = SD funzionerebbe per UTF-8; per gli altri, avresti bisogno di PERLIO.
Cristo

1
Forse una versione un po 'più breve:awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1'
TrueY

122

Utilizzando GNU sed(su Linux o Cygwin):

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

Su FreeBSD:

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

Vantaggio dell'uso di GNU o FreeBSD sed: il -iparametro significa "in place" e aggiornerà i file senza bisogno di reindirizzamenti o strani trucchi.

Su Mac:

Questa awksoluzione in un'altra risposta funziona , ma il sedcomando sopra non funziona. Almeno su Mac (Sierra) la seddocumentazione non menziona il supporto dell'escaping esadecimale ala \xef.

Un trucco simile può essere ottenuto con qualsiasi programma collegandosi allo spongestrumento da moreutils :

awk '…' INFILE | sponge INFILE

5
Ho provato il secondo comando proprio su Mac OS X e il risultato è stato "successo", ma la sostituzione non è avvenuta effettivamente.
Trejkaz

1
Vale la pena notare che questi comandi sostituiscono una specifica sequenza di byte, che è uno dei possibili byte-order-mark . Forse il tuo file aveva una sequenza BOM diversa. (Non posso fare a meno di questo, dato che non ho un Mac)
Denilson Sá Maia

3
Quando ho provato il secondo comando su OS X su un file che utilizzava 0xef 0xbb 0xbf come BOM, in realtà non ha eseguito la sostituzione.
John Wiseman

In OSX, potevo farlo funzionare solo tramite perl, come mostrato qui: stackoverflow.com/a/9101056/2063546
Ian

Su OS X El Capitan 10.11.6, questo non funziona, ma la risposta ufficiale stackoverflow.com/a/1068700/9636 funziona bene.
Heath Borders

42

Non strano, ma più semplice:

tail -c +4 UTF8 > UTF8.nobom

Per verificare la distinta base:

hd -n 3 UTF8

Se BOM è presente vedrai: 00000000 ef bb bf ...


6
Le distinte materiali sono 2 byte per UTF-16 e 4 byte per UTF-32 e, naturalmente, non hanno nulla a che fare con UTF-8 in primo luogo.
Cristo

2
@KarolyHorvath Sì, precisamente. Il suo utilizzo è sconsigliato. Rompe le cose. La codifica dovrebbe essere specificata da un protocollo di livello superiore.
tchrist

1
@tchrist: vuoi dire che rompe cose rotte? :) le app appropriate dovrebbero essere in grado di gestire quella distinta base.
Karoly Horvath

7
@KarolyHorvath Voglio dire che interrompe molti programmi . Non è quello che ho detto? Quando apri un flusso nelle codifiche UTF-16 o UTF-32, il decoder sa di non contare la distinta componenti. Quando si utilizza UTF-8, i decoder presentano la distinta materiali come dati. Questo è un errore di sintassi in innumerevoli programmi. Anche il decoder Java si comporta in questo modo, BY DESIGN! Le distinte materiali sui file UTF-8 sono fuori posto e un rompicoglioni: sono un errore! Rompono molte cose. Anche solo cat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8sarà rotto. Non utilizzare mai una distinta base su UTF-8. Periodo.
tchrist

6
hdnon è disponibile su OS X (a partire da 10.8.2), in modo da verificare la presenza di un UTF-8 BOM lì è possibile utilizzare il seguente: head -c 3 file | od -t x1.
mklement0

21

Oltre a convertire le terminazioni di riga CRLF in LF, dos2unixrimuove anche le distinte materiali:

dos2unix *.txt

dos2unix converte anche i file UTF-16 con una BOM (ma non i file UTF-16 senza BOM) in UTF-8 senza BOM:

$ 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

3

So che la domanda era rivolta a unix / linux, ho pensato che varrebbe la pena menzionare una buona opzione per unix-challenge (su Windows, con un'interfaccia utente).
Mi sono imbattuto nello stesso problema su un progetto WordPress (BOM stava causando problemi con feed RSS e convalida della pagina) e ho dovuto esaminare tutti i file in un albero di directory abbastanza grande per trovare quello che era con BOM. Trovato un'applicazione chiamata Replace Pioneer e in essa:

Batch Runner -> Cerca (per trovare tutti i file nelle sottocartelle) -> Sostituisci modello -> Binario rimuovi BOM (c'è un modello di ricerca e sostituzione già pronto per questo).

Non era la soluzione più elegante e richiedeva l'installazione di un programma, il che è uno svantaggio. Ma una volta scoperto cosa mi stava succedendo, ha funzionato a meraviglia (e ho trovato 3 file su circa 2300 che erano con BOM).


1
Sono così felice quando ho trovato la tua soluzione, tuttavia non ho il privilegio di installare il software sul computer aziendale. Ci è voluto molto tempo oggi, finché non ho trovato l'alternativa: usare Notepad ++ con il plugin PythonScript. superuser.com/questions/418515/… Grazie comunque!
Hoàng Long
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.