TL; DR:
grep -axv '.*' out.txt
resposta longa
Ambas as respostas atuais são extremamente enganosas e basicamente erradas.
Para testar, obtenha esses dois arquivos (de um desenvolvedor muito conceituado: 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
O primeiro UTF-8-demo.txt
é um arquivo projetado para mostrar como o UTF-8 é capaz de apresentar muitos idiomas, matemática, braille e muitos outros tipos úteis de caracteres. Dê uma olhada com um editor de texto (que entende utf-8) e você verá muitos exemplos e não �
.
O teste que uma resposta propõe: limitar o intervalo de caracteres \x00-\x7F
rejeitará quase tudo dentro deste arquivo.
Isso está muito errado e não removerá nenhum, �
pois não há nenhum nesse arquivo .
O uso do teste recomendado nessa resposta removerá 72.5 %
o arquivo:
$ grep -oP "[^\x00-\x7F]" UTF-8-demo.txt | tr -d '\n' | wc -c
10192
$ cat UTF-8-demo.txt | wc -c
14058
Isso é (para propósitos mais práticos) o arquivo inteiro. Um arquivo muito bem projetado para mostrar caracteres perfeitamente válidos.
Teste
O segundo arquivo foi projetado para tentar vários casos de borda para confirmar que os leitores utf-8 estão fazendo um bom trabalho. Ele contém dentro de muitos caracteres que farão com que um ' ' seja mostrado. Mas a outra recomendação de resposta (a selecionada) a ser usada file
falha bastante nesse arquivo. Somente a remoção de um byte zero ( \0
) (que tecnicamente é ASCII válido) e um \x7f
byte (DEL - delete) (que também é claramente um caractere ASCII) tornará todo o arquivo válido para o 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
Não apenas file
falha na detecção dos muitos caracteres incorretos, mas também na detecção e no relatório de que é um arquivo codificado em UTF-8.
E sim, file
é capaz de detectar e relatar texto codificado em UTF-8:
$ echo "ééakjfhhjhfakjfhfhaéá" | file -
/dev/stdin: UTF-8 Unicode text
Além disso, file
falha ao relatar como ASCII a maioria dos caracteres de controle no intervalo de 1 a 31. Ele ( file
) relata alguns intervalos como data
:
$ printf '%b' "$(printf '\\U%x' {1..6})" | file -
/dev/stdin: data
Outros como ASCII text
:
$ printf '%b' "$(printf '\\U%x' 7 {9..12})" | file -
/dev/stdin: ASCII text
Como o intervalo de caracteres imprimíveis (com novas linhas):
$ printf '%b' "$(printf '\\U%x' {32..126} 10)" | file -
/dev/stdin: ASCII text
Mas alguns intervalos podem causar resultados estranhos:
$ printf '%b' "$(printf '\\U%x' {14..26})" | file -
/dev/stdin: Atari MSA archive data, 4113 sectors per track, starting track: 5141, ending track: 5655
O programa file
não é uma ferramenta para detectar texto, mas para detectar números mágicos em programas ou arquivos executáveis.
Os intervalos file
detectam e o tipo correspondente relatado que encontrei foram:
Valores de um 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
Intervalos codificados 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
Uma solução possível está abaixo.
Resposta anterior.
O valor Unicode para o personagem que você está postando é:
$ printf '%x\n' "'�"
fffd
Sim, esse é um caractere Unicode 'REPLACEMENT CHARACTER' (U + FFFD) . Esse é um caractere usado para substituir qualquer caractere Unicode inválido encontrado no texto. É um "auxílio visual", não um personagem real. Para localizar e listar todas as linhas completas que contêm caracteres UNICODE inválidos , use:
grep -axv '.*' out.txt
mas se você quiser detectar apenas se algum caractere é inválido, use:
grep -qaxv '.*' out.txt; echo $?
Se o resultado for que 1
o arquivo está limpo, caso contrário, será zero 0
.
Se o que você estava perguntando era: como encontrar o �
personagem, use o seguinte:
➤ a='Basically, if the file "out.txt" contains "�" anywhere in the file I'
➤ echo "$a" | grep -oP $(printf %b \\Ufffd)
�
Ou, se o seu sistema processar texto UTF-8 corretamente, simplesmente:
➤ echo "$a" | grep -oP '�'
�
grep
long compreende o unicode (o que o torna muito mais lento, portanto, para procurar por seqüências ascii, aLANG=C grep
é uma grande melhoria de desempenho).