Come posso rimuovere la DBA da un file UTF-8?


64

Ho un file in codifica UTF-8 con BOM e voglio rimuovere la BOM. Esistono strumenti da riga di comando di Linux per rimuovere la distinta componenti dal file?

$ file test.xml
test.xml:  XML 1.0 document, UTF-8 Unicode (with BOM) text, with very long lines


1
Ho creato uno strumento molto semplice per farlo solo qualche mese fa: oskog97.com/read/?path=/small-scripts/killbom&referer=/… Potrebbe valere la pena installare qualcosa di simile in / usr / local / bin se hai molti file codificati UTF-8 con DBA.
Oskar Skog,

Risposte:


76

Se non sei sicuro che il file contenga una DBA UTF-8, questo (supponendo che l'implementazione GNU sia sed) rimuoverà la DBA se esiste o non apporterà alcuna modifica in caso contrario.

sed '1s/^\xEF\xBB\xBF//' < orig.txt > new.txt

Puoi anche sovrascrivere il file esistente con l' -iopzione:

sed -i '1s/^\xEF\xBB\xBF//' orig.txt

4
questo potrebbe non funzionare in una locale utf8, ma anteporre una sostituzione locale a c o posix funzionerà sempre.
Hildred

3
@hildred L'ho provato con le impostazioni en_US.UTF-8locali e ha funzionato. Quando fallirà?
m13r,

2
@ m13r, dipende dalla versione di sed e dalle opzioni di compilazione. In caso di fallimento, una nuovissima versione di sed con classi di caratteri Unicode inserirà la sequenza di tre byte come un singolo carattere che non corrisponde alla sequenza di tre caratteri. Tuttavia, in tal caso è possibile eseguire una corrispondenza di caratteri a sedici bit. Tuttavia questa è una nuova funzionalità e non universalmente presente. Se vuoi provare ti consiglio di compilare l'ultima versione.
Hildred

4
Per risolverlo in modo che funzioni con un sed abilitato per Unicode LC_ALL = C sed '1s / ^ \ xEF \ xBB \ xBF //'
Joshua

1
@mazunki, 1s/significa solo cercare la prima riga; le altre linee non sono interessate. I ^mezzi corrispondono solo all'inizio della (prima) riga. \xEF\xBB\xBFè la distinta base UTF-8 (stringa esadecimale con escape). //significa sostituire con niente. Avrei potuto aggiungere 1alla fine (per 1s/^xEF\xBB\xBF//1), il che significherebbe corrispondere solo alla prima occorrenza del modello sulla linea. Ma poiché la ricerca è ancorata ^, questo non farà alcuna differenza. Se il file non ha la DBA all'inizio della prima riga, il modello non corrisponderà e quindi non viene apportata alcuna modifica.
CSM

64

Una distinta base non ha senso in UTF-8. Questi vengono generalmente aggiunti per errore da software fasulli su sistemi operativi Microsoft.

dos2unix lo rimuoverà e si occuperà anche di altre idiosincrasie dei file di testo di Windows.

dos2unix test.xml

17
Sono d'accordo sul fatto che una distinta base codificata UTF-8 non abbia senso, ma che ci crediate o no, ci sono molte persone che pensano che sia un'ottima idea che aiuti a differenziare UTF-8 dalle altre codifiche a 8 bit. Quindi è una questione di gusti. Blocco note di Windows aggiunge una DBA appositamente.
Johan Myréen,

17
Cosa importa se ha senso o meno, quando il contesto è solo una domanda su come rimuoverlo? Secondo Wikipedia, Notepad richiede che la distinta componenti riconosca un file come UTF-8 e Google Docs lo aggiunge anche durante l'esportazione di un file come testo. Dubito che lo facciano tutti per errore .
ilkkachu,

I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
terdon

1
Esiste un modo per non convertire le terminazioni di riga e rimuovere semplicemente la distinta componenti dos2unix?
m13r,

2
@ m13r Quindi usa lo script sed in questa risposta . Ciò rimuoverà solo il bom (se esiste), nient'altro verrà modificato.
Arrow,

27

È possibile rimuovere la DBA da un file con il tailcomando:

tail -c +4 withBOM.txt > withoutBOM.txt

2
Perché 4? La DBA ha 3 byte.
deviantfan,

10
@deviantfan Ecco perché è necessario iniziare dal 4 ° byte se si desidera ignorarlo.
Stéphane Chazelas,

9
tailsta usando l'indicizzazione basata su 1 ?! WTF!
CodesInChaos,

5
@CodesInChaos tail -c -1o tail -c 1(ciò che tailviene generalmente utilizzato) è il contenuto che inizia con l'ultimo byte, a tail -c +1partire dal primo byte. tail -c 0/ tail -c +0per quello sarebbe molto più poco intuitivo.
Stéphane Chazelas,

2
@deviantfan: (dd bs=1 count=3 of=/dev/null; cat) <input >output. O con GNU (head -c3 >/dev/null; cat)- anche in UTF8 o altre impostazioni internazionali non a byte singolo; La testa GNU fa 'char' = byte.
dave_thompson_085

20

Utilizzando VIM

  1. Apri file in VIM:

    vi text.xml
    
  2. Rimuovi codifica DBA:

    :set nobomb
    
  3. Salva ed esci:

    :wq
    

Stranamente con vim 8 su un mac, ho un file csv utf-8 creato da Excel e inizia con <feff>, ma :set nobombnon lo modifica né lo rimuove.
dlamblin

5

Puoi usare

LANG=C LC_ALL=C sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- filename

per rimuovere il contrassegno dell'ordine dei byte dall'inizio del file, se presente, e convertire qualsiasi nuova riga CR LF in LF. La LANG=C LC_ALL=Cracconta il guscio si desidera che il comando venga eseguito nel locale di default C (noto anche come l'impostazione internazionale predefinita POSIX), dove i tre byte che costituiscono il Byte Order Mark vengono considerati byte. L' -iopzione di sed significa sul posto. Se lo usi -i.old, sed salva il file originale come filename.olde il nuovo file (con le eventuali modifiche) come filename.


Personalmente mi piace avere questo come ~/bin/fix-ms; per esempio, come

#!/bin/dash
export LANG=C LC_ALL=C
if [ $# -gt 0 ]; then
    for FILE in "$@" ; do
        sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$FILE" || exit 1
    done
else
    exec sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//'
fi

quindi se devo applicare questo per dire tutti i file sorgente e le intestazioni C (il mio vecchio codice dell'era MS-DOS, per esempio!), ho appena eseguito

find . -name '*.[CHch]' -print0 | xargs -r0 ~/bin/ms-fix

o, se voglio solo guardare un tale file, senza modificarlo, posso eseguire

~/bin/ms-fix < filename | less

e non vedere il brutto <U+FEFF>nel mio terminale UTF-8.


Perché non semplicemente sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"?
Stéphane Chazelas,

@ StéphaneChazelas: Perché voglio che lo script esca immediatamente se c'è un problema con una sostituzione, che sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"non funziona; restituisce un codice di uscita, ma elabora tutti i file elencati nell'elenco degli argomenti prima di uscire.
Animale nominale

@ StéphaneChazelas: I --nomi prima dei file sono ovviamente importanti: senza di essa, i nomi dei file che iniziano con un trattino possono essere considerati opzioni da sed. Ho modificato quelli nella mia risposta; Grazie per il promemoria!
Animale nominale

0

Recentemente ho trovato questo piccolo strumento da riga di comando che aggiunge o rimuove la distinta base dai file codificati UTF-8 arbitrari: UTF BOM Utils ( nuovo link su github)

Piccolo inconveniente, puoi scaricare solo il semplice codice sorgente C ++. Devi creare il makefile (con CMake , per esempio) e compilarlo da solo, i binari non sono forniti in questa pagina.

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.