2009-07-01 12 views

risposta

105

Try this:

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

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

o leggermente più corta, utilizzando le conoscenze che l'azione predefinita in awk è quello di stampare il record:

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

1 è la condizione più breve che restituisce sempre vero, così ogni record viene stampato.

Divertiti!

- ADDENDUM -

Unicode Byte Order Mark (BOM) FAQ include la seguente tabella elenca l'esatto BOM byte per ogni 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 

Così, si può vedere come \xef\xbb\xbf corrisponde a EF BB BFUTF-8 BOM byte da la tabella sopra.

+1

sembra che il punto in mezzo della dichiarazione sub è troppo (almeno, il mio awk lamenta). Accanto a questo è esattamente quello che ho cercato, grazie! – Boldewyn

+4

Questa soluzione, tuttavia, funziona ** solo ** per i file codificati UTF-8. Per gli altri, come UTF-16, consultare Wikipedia per la rappresentazione BOM corrispondente: http://en.wikipedia.org/wiki/Byte_order_mark – Boldewyn

+0

Sono d'accordo con il commento precedente; il punto non appartiene al centro di questa affermazione e rende questo piccolo frammento altrimenti un esempio di un errore di sintassi awk. –

40

Non awk, ma più semplice:

tail -c +4 UTF8 > UTF8.nobom 

Per verificare la presenza di BOM:

hd -n 3 UTF8 

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

+0

Il trucco della coda è bello. Grazie! – Boldewyn

+5

BOM sono 2 byte per UTF-16 e 4 byte per UTF-32 e, naturalmente, non hanno attività in UTF-8 in primo luogo. – tchrist

+0

@tchrist: da wikipedia: "Lo standard Unicode consente il BOM in UTF-8, ma non ne richiede o ne consiglia l'uso. L'ordine byte non ha significato in UTF-8, quindi in UTF-8 la distinta base serve solo a ** identificare ** un flusso di testo o un file come UTF-8. " –

119

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 di usare GNU o FreeBSD sed: il parametro -i significa "a posto", e aggiornerà i file senza la necessità di reindirizzamenti o trucchi strani.

Su Mac:

This awk solution in another answer works, ma il comando sed sopra non funziona. Almeno su Mac (Sierra) la documentazione sed non menziona il supporto per l'escape esadecimale ala \xef.

Un trucco simile può essere ottenuto con qualsiasi programma dalla tubazione allo strumento sponge da moreutils:

awk '…' INFILE | sponge INFILE 
+5

Ho provato il secondo comando con precisione su Mac OS X e il risultato è stato "successo", ma la sostituzione non si è effettivamente verificata. – Trejkaz

+0

Vale la pena notare che questi comandi sostituiscono una sequenza di byte specifica, che è [uno dei possibili byte-order-marks] (http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding). Forse il tuo file ha avuto una sequenza BOM diversa. (Non posso fare a meno di questo, dato che non ho un Mac) –

+3

Quando ho provato il secondo comando su OS X su un file che utilizzava 0xef 0xbb 0xbf come BOM, in realtà non eseguiva la sostituzione. –

2

So che la domanda era rivolta a Unix/Linux, pensato che varrebbe la pena di parlare di una buona opzione per unix-challenge (su Windows, con un'interfaccia utente).
Mi sono imbattuto nello stesso problema in un progetto WordPress (la distinta base 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 -> Ricerca (per trovare tutti i file nelle sottocartelle) -> Sostituire Template -> Binary rimuovere BOM (v'è una ricerca fatta pronta e sostituire modello per questo) .

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

+1

Sono così felice quando ho trovato la soluzione, ma non ho il privilegio di installare il software sul computer aziendale. Ci sono voluti un sacco di tempo oggi, finché non ho trovato l'alternativa: usare Notepad ++ con il plugin PythonScript. http://superuser.com/questions/418515/how-to-find-all-files-in-directory-that-taintain-utf-8-bom-byte-order-mark/914116#914116 Grazie comunque! –

18

Oltre a convertire i fine riga CRLF a LF, dos2unix rimuove anche le distinte base:

dos2unix *.txt 

dos2unix converte anche UTF-16 file con una distinta base (ma non UTF-16 file senza un BOM) a 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 
Problemi correlati