grep
è lo strumento sbagliato per il lavoro.
Vedrai � U+FFFD REPLACEMENT CHARACTER
non perché è letteralmente nel contenuto del file, ma perché hai guardato un file binario con uno strumento che dovrebbe gestire solo l'input basato su testo. Il modo standard per gestire input non validi (ovvero dati binari casuali) è sostituire tutto ciò che non è valido nella locale corrente (molto probabilmente UTF-8) con U+FFFD prima che venga visualizzato sullo schermo.
Ciò significa che è molto probabile che un \xEF\xBF\xBD
letterale (la sequenza di byte UTF-8 per il carattere U+FFFD) non compare mai nel file. grep
ha perfettamente ragione a dirti che non ce n'è.
Un modo per rilevare se un file contiene qualche binario sconosciuto è con il file(1)
comando:
$ head -c 100 /dev/urandom > rubbish.bin
$ file rubbish.bin
rubbish.bin: data
Per qualsiasi tipo di file sconosciuto dirà semplicemente data
. Prova
$ file out.txt | grep '^out.txt: data$'
per verificare se il file contiene davvero binari arbitrari e quindi molto probabilmente spazzatura.
Se vuoi assicurarti che out.txt
è solo un file di testo con codifica UTF-8, in alternativa puoi usare iconv
:
$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
TL;DR:
grep -axv '.*' out.txt
risposta lunga
Entrambe le risposte attuali sono estremamente fuorvianti e fondamentalmente sbagliate.
Per testare, prendi 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
Demo
Il primo UTF-8-demo.txt
è un file progettato per mostrare quanto bene 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 proposto da una risposta:limitare l'intervallo di caratteri a \x00-\x7F
rifiuterà quasi tutto all'interno di questo file.
Questo è molto sbagliato e non rimuoverà alcun �
poiché non ce n'è nessuno in quel file .
L'utilizzo del test consigliato in quella risposta rimuoverà 72.5 %
del 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.
Prova
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 faranno apparire un '�'. Ma l'altra raccomandazione di risposta (quella selezionata) per utilizzare file
fallisce gravemente con questo file. Solo rimuovendo un byte zero (\0
) (che tecnicamente è un ASCII valido) e un \x7f
byte (DEL - delete) (che è chiaramente anche un carattere ASCII) renderà all il file valido 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 file
non riescono a rilevare i molti caratteri errati, ma non riesce nemmeno a rilevare e segnalare che si tratta di un file con codifica UTF-8.
E sì, file
è in grado di rilevare e segnalare il testo con codifica 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. It (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 stampabili (con newline):
$ 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 la magia numeri in programmi o file eseguibili.
Gli intervalli file
detect, e il tipo corrispondente riportato che ho trovato era:
-
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 con codifica 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 si trova sotto.
Risposta precedente.
Il valore Unicode per il carattere che stai postando è:
$ printf '%x\n' "'�"
fffd
Sì, questo è un carattere Unicode 'CARATTERE SOSTITUTIVO' (U+FFFD). Questo è un carattere utilizzato per sostituire qualsiasi non valido Carattere Unicode trovato nel testo. È un "ausilio visivo", non un vero e proprio personaggio. Per trovare ed elencare ogni riga completa che contiene UNICODE non valido i caratteri usano:
grep -axv '.*' out.txt
ma se vuoi solo rilevare se qualche carattere non è valido, usa:
grep -qaxv '.*' out.txt; echo $?
Se il risultato è 1
il file è pulito, altrimenti sarà zero 0
.
Se quello che stavi chiedendo era:come trovare il �
carattere, quindi, usa questo:
➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�
Oppure, se il tuo sistema elabora correttamente il testo UTF-8, semplicemente:
➤ echo "$a" | grep -oP '�'
�
Questa primissima risposta era per il post originale che era:
Come grep per unicode � in uno script bash
if grep -q "�" out.txt then echo "working" else cat out.txt fi
Fondamentalmente, se il file "out.txt" contiene "�" in qualsiasi punto del file, vorrei che echo "funzionante" E se il file "out.txt" NON contiene "�" in qualsiasi punto del file, allora mi piacerebbe to cat out.txt
Prova
grep -oP "[^\x00-\x7F]"
con un if .. then
dichiarazione come segue:
if grep -oP "[^\x00-\x7F]" file.txt; then
echo "grep found something ..."
else
echo "Nothing found!"
fi
Spiegazione:
-P
,--perl-regexp
:PATTERN è un'espressione regolare Perl-o
,--only-matching
:mostra solo la parte di una linea corrispondente a PATTERN[^\x00-\x7F]
è una regex che corrisponde a un singolo carattere non ASCII.[[:ascii:]]
- corrisponde a un singolo carattere ASCII[^[:ascii:]]
- corrisponde a un singolo carattere non ASCII
in bash
LC_COLLATE=C grep -o '[^ -~]' file