2015-11-28 8 views
14

Sto provando a scrivere uno script che rimuoverà automaticamente i BOM UTF-8 da un file. Sto riscontrando problemi nel rilevare se il file ne ha uno al primo posto oppure no. Ecco il mio codice:Come rilevare se un file ha un BOM UTF-8 in Bash?

function has-bom { 
    # Test if the file starts with 0xEF, 0xBB, and 0xBF 
    head -c 3 "$1" | grep -P '\xef\xbb\xbf' 
    return $? 
} 

Per qualche ragione, head sembra ignorare la distinta di fronte al file. Ad esempio, l'esecuzione di questo

printf '\xef\xbb\xbf' > file 
head -c 3 file 

non stampa nulla.

Ho provato a cercare un'opzione in head --help che mi permettesse di aggirare questo problema, ma senza fortuna. C'è qualcosa che posso fare per farlo funzionare?

risposta

11

In primo luogo, cerchiamo di dimostrare che head è in realtà funziona correttamente:

$ printf '\xef\xbb\xbf' >file 
$ head -c 3 file 
$ head -c 3 file | hexdump -C 
00000000 ef bb bf           |...| 
00000003 

Ora, creiamo una funzione di lavoro has_bom. Se il vostro grep supporta -P, allora una possibilità è:

$ has_bom() { head -c3 "$1" | LC_ALL=C grep -qP '\xef\xbb\xbf'; } 
$ has_bom file && echo yes 
yes 

Attualmente, solo GNU grep supporta -P.

Un'altra opzione è quella di usare di $'...' bash:

$ has_bom() { head -c3 "$1" | grep -q $'\xef\xbb\xbf'; } 
$ has_bom file && echo yes 
yes 

ksh e zsh supportano anche $'...' ma questo costrutto non è POSIX e dash non lo supporta.

Note:

  1. L'uso di un esplicito return $? è opzionale. La funzione, di default, ritornerà con il codice di uscita dell'ultimo comando eseguito.

  2. Ho utilizzato il modulo POSIX per definire le funzioni. Questo è equivalente al modulo di bash ma ti dà un problema in meno da affrontare se dovessi eseguire la funzione sotto un'altra shell.

  3. bash accetta l'uso del carattere - in un nome di funzione ma questa è una funzionalità controversa. L'ho sostituito con _ che è più ampiamente accettato. (Per ulteriori informazioni su questo problema, vedere this answer.)

  4. L'opzione -q-grep rende tranquillo, nel senso che pone ancora un codice di uscita corretta, ma non invia alcun carattere sullo standard output.

+1

Eh, non ho mai saputo che Bash supportava letterali stringa esadecimale. Comunque, grazie per l'ottima risposta! –

+0

ciao, posso chiedere in linea 'head -c 3 file | hexdump -c ', cosa fa il' -c'?Il precedente sembra 1) limitare il numero di caratteri in uscita 2) limitare il numero di linea (forse) a 0000000 e 0000003; ma quest'ultimo rende l'output, che dovrebbe essere "be bf" ecc., nel marker di sostituzione. Sto usando bash e test su un file di testo generato in Windows, codifica originale = GB18030. Grazie. – CrazyFrog

+0

@CrazyFrog 'head -c 3 file' scrive i primi tre caratteri di' file' come standard. 'hexdump -C' formatta quei caratteri in modo umano come esadecimale. – John1024

0

I applicate le seguenti per la prima linea di lettura:

read c 
if (("$(printf "%d" "'${c:0:1}")" == 65279)) ; then c="${c:1}" ; fi 

Questo rimuove semplicemente la distinta dalla variabile.

Problemi correlati