TL; DR:
grep -axv '.*' out.txt
risposta lunga
Entrambe le risposte presenti sono estremamente fuorvianti e sostanzialmente sbagliate.
Per testare, scarica questi due file (da uno sviluppatore molto apprezzato: Markus Kuhn):
$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt
$ wget https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
dimostrazione
Il primo UTF-8-demo.txt
è un file progettato per mostrare quanto UTF-8 sia in grado di presentare molte lingue, matematica, braille e molti altri utili tipi di caratteri. Dai un'occhiata con un editor di testo (che capisce utf-8) e vedrai molti esempi e no �
.
Il test che una risposta propone: limitare la gamma di caratteri \x00-\x7F
rifiuterà quasi tutto all'interno di questo file.
Questo è molto sbagliato e non ne rimuoverà nessuno �
perché non ce n'è nel file .
L'utilizzo del test consigliato in quella risposta rimuoverà 72.5 %
il file:
$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058
Questo è (per la maggior parte degli scopi pratici) l'intero file. Un file molto ben progettato per mostrare caratteri perfettamente validi.
Test
Il secondo file è progettato per provare diversi casi limite per confermare che i lettori utf-8 stanno facendo un buon lavoro. Contiene al suo interno molti caratteri che causano la visualizzazione di un ' '. Ma l'altra raccomandazione di risposta (quella selezionata) da utilizzare file
non ha esito positivo con questo file. Rimuovere solo un byte zero ( \0
) (che tecnicamente è valido ASCII) e un \x7f
byte (DEL - cancella) (che è chiaramente anche un carattere ASCII) renderà valido tutto il file per il file
comando:
$ cat UTF-8-test.txt | tr -d '\0\177' > a.txt
$ file a.txt
a.txt: Non-ISO extended-ASCII text, with LF, NEL line terminators
Non solo non file
riesce a rilevare i molti caratteri errati, ma non riesce anche a rilevare e segnalare che si tratta di un file codificato UTF-8.
E sì, file
è in grado di rilevare e segnalare il testo codificato UTF-8:
$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text
Inoltre, file
non riesce a riportare come ASCII la maggior parte dei caratteri di controllo nell'intervallo da 1 a 31. ( file
) riporta alcuni intervalli come data
:
$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data
Altri come ASCII text
:
$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text
Come intervallo di caratteri stampabile (con nuove righe):
$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text
Ma alcuni intervalli possono causare risultati strani:
$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655
Il programma file
non è uno strumento per rilevare il testo, ma per rilevare numeri magici in programmi o file eseguibili.
Gli intervalli file
rilevati e il tipo corrispondente riportato che ho trovato erano:
Valori di un byte, principalmente ascii:
{1..6} {14..26} {28..31} 127 :data
{128..132} {134..159} :Non-ISO extended-ASCII text
133 :ASCII text, with LF, NEL line terminators
27 :ASCII text, with escape sequences
13 :ASCII text, with CR, LF line terminators
8 :ASCII text, with overstriking
7 {9..12} {32..126} :ASCII text
{160..255} :ISO-8859 text
Intervalli codificati Utf-8:
{1..6} {14..26} {28..31} 127 :data
27 :ASCII text, with escape sequences
13 :ASCII text, with CR, LF line terminators
8 :ASCII text, with overstriking
7 {9..12} {32..126} :ASCII text
{128..132} {134..159} :UTF-8 Unicode text
133 :UTF-8 Unicode text, with LF, NEL line terminators
{160..255} :UTF-8 Unicode text
{256..5120} :UTF-8 Unicode text
Una possibile soluzione è la seguente.
Risposta precedente
Il valore Unicode per il personaggio che stai postando è:
$ printf '%x\n' "'�"
fffd
Sì, si tratta di un carattere Unicode 'REPLACEMENT CHARACTER' (U + FFFD) . Questo è un carattere usato per sostituire qualsiasi carattere Unicode non valido trovato nel testo. È un "aiuto visivo", non un vero personaggio. Per trovare ed elencare ogni riga completa che contiene caratteri UNICODE non validi , utilizzare:
grep -axv '.*' out.txt
ma se vuoi rilevare solo se un personaggio non è valido, usa:
grep -qaxv '.*' out.txt; echo $?
Se il risultato è che 1
il file è pulito, altrimenti sarà zero 0
.
Se quello che stavi chiedendo era: come trovare il �
personaggio, usa questo:
➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�
O se il tuo sistema elabora correttamente il testo UTF-8, semplicemente:
➤ echo "$a" | grep -oP '�'
�
grep
a lungo capisce unicode (che lo rende molto più lento, quindi per cercare stringhe ASCII, aLANG=C grep
è un enorme miglioramento delle prestazioni).