Como grep para unicode em um script bash

10
if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt
fi

Basicamente, se o arquivo "out.txt" contiver " " em qualquer lugar do arquivo, gostaria que ele ecoasse "funcionando" E se o arquivo "out.txt" NÃO contiver " " em qualquer lugar do arquivo, eu gostaria para cat out.txt

EDIT: Então aqui está o que estou fazendo. Estou tentando fazer força bruta e descriptografar openssl.

openssl enc retorna 0 em caso de sucesso, diferente de zero. Nota: você obterá falsos positivos porque o AES / CBC só pode determinar se a "descriptografia funciona" com base na correção do preenchimento. Portanto, o arquivo descriptografa, mas não será a senha correta e, portanto, terá bobagens. Um personagem comum no jargão é " ". Então, eu quero que o loop continue, se a saída contiver " ".

Heres meu link git https://github.com/Raphaeangelo/OpenSSLCracker Heres o script

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null && printf "==================================================\n"
if grep -q "�" out.txt
    then
        :
    else
        cat out.txt &&
            printf "\n==================================================" &&
            printfn"\npassword is $line\n" &&
            read -p "press return key to continue..." < /dev/tty; 
fi
done < ./password.txt

Ainda está me mostrando saída com o `` charicter '' nele

UPDATE: Resolvido

printf "Working..."

while read line
do
openssl aes-256-cbc -d -a -in $1 -pass pass:$line -out out.txt 2>out.txt >/dev/null
if file out.txt | grep -q 'out.txt: ASCII text'
    then
        printf "\n==================================================\n\n" &&
            cat out.txt &&
            printf "\n==================================================" &&
            printf "\npassword is $line\n" && 
            read -p "press return key to continue..." < /dev/tty;
    else
        : 
fi
done < ./password.txt
Stuart Sloan
fonte
Parece correto, deve funcionar (btw, não tenho fonte para o seu personagem unicode ver, mas nenhum deles tem algum significado especial). greplong compreende o unicode (o que o torna muito mais lento, portanto, para procurar por seqüências ascii, a LANG=C grepé uma grande melhoria de desempenho).
peterh - Restabelece Monica
Talvez eu tenha que excluir isso e postar outra pergunta, porque tenho certeza de que estou confundindo todo mundo aqui.
Stuart Sloan
@Stuart Sloan, o título da sua pergunta é: How to grep for unicode � in a bash scripté isso mesmo que você quer? extrair o unicode? esclareça para que possamos ajudar!
1
@Goro Fiz a edição no meu post original. Eu espero que faça sentido. Informe-me se não aparecer e tentarei esclarecer.
Stuart Sloan
1
Ambas as respostas atuais são extremamente enganosas. Por favor, leia (novamente) minha resposta , editei-a para explicar o que está errado com ambas as respostas.
Isaac

Respostas:

27

grep é a ferramenta errada para o trabalho.

Você vê o `` U+FFFD REPLACEMENT CHARACTERnão porque está literalmente no conteúdo do arquivo, mas porque você olhou para um arquivo binário com uma ferramenta que deveria lidar apenas com entrada baseada em texto. A maneira padrão de lidar com entradas inválidas (ou seja, dados binários aleatórios) é substituir tudo o que não é válido no código do idioma atual (provavelmente UTF-8) por U + FFFD antes que ele atinja a tela.

Isso significa que é muito provável que um literal \xEF\xBF\xBD(a sequência de bytes UTF-8 para o caractere U + FFFD) nunca ocorra no arquivo. greptem toda a razão em dizer que não há.

Uma maneira de detectar se um arquivo contém algum binário desconhecido é com o file(1)comando:

$ head -c 100 /dev/urandom > rubbish.bin
$ file rubbish.bin
rubbish.bin: data

Para qualquer tipo de arquivo desconhecido, basta dizer data. Experimentar

$ file out.txt | grep '^out.txt: data$'

para verificar se o arquivo realmente contém algum binário arbitrário e, portanto, provavelmente lixo.

Se quiser ter certeza de que out.txté apenas um arquivo de texto codificado em UTF-8, você também pode usar iconv:

$ iconv -f utf-8 -t utf-16 out.txt >/dev/null
Boldewyn
fonte
Você está exatamente certo! infelizmente, ainda estou recebendo alguns (menos do que antes) lixo na saída.
Stuart Sloan #
Possivelmente filedetecta algum outro tipo de conteúdo para esses arquivos. Se você 100% sempre esperam apenas UTF-8 arquivos de texto codificados, você pode verificar com iconv, se um arquivo é válido UTF-8: iconv -f utf-8 -t utf-16 out.txt >/dev/null. Se iconvnão puder converter o arquivo devido a seqüências UTF-8 inválidas, ele retornará com um código de saída diferente de zero.
Boldewyn
2
O comando file estava certo! Você me ajudou a resolver meu problema, obrigado!
Stuart Sloan
4
Claro que o grep "é a ferramenta para o trabalho", tente grep -axv '.*' badchars.txt. Isso imprimirá qualquer linha que contenha qualquer caractere Unicode inválido .
Isaac
1
Isso é extremamente enganador, por favor, leia minha resposta sobre o que filefaz.
Isaac
5

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-\x7Frejeitará 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 filefalha bastante nesse arquivo. Somente a remoção de um byte zero ( \0) (que tecnicamente é ASCII válido) e um \x7fbyte (DEL - delete) (que também é claramente um caractere ASCII) tornará todo o arquivo válido para o filecomando:

$ 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 filefalha 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, filefalha 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 filenão é uma ferramenta para detectar texto, mas para detectar números mágicos em programas ou arquivos executáveis.

Os intervalos filedetectam 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 1o 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 '�'
�
Isaac
fonte
OMG muito obrigado por grep -axv '.*' !! Eu lutei com alguns caracteres ruins nos meus arquivos de texto e como corrigi-los no emacs, por uma década ou duas !!!
Nellmcb
3

Essa resposta foi muito cedo para o post original, que era:

Como grep para unicode em um script bash

if grep -q "�" out.txt
    then
        echo "working"
    else
        cat out.txt  fi

Basicamente, se o arquivo "out.txt" contiver " " em qualquer lugar do arquivo, gostaria que ele ecoasse "funcionando" E se o arquivo "out.txt" NÃO contiver " " em qualquer lugar do arquivo, eu gostaria para cat out.txt

Experimentar

grep -oP "[^\x00-\x7F]"

com uma if .. thendeclaração da seguinte maneira:

if grep -oP "[^\x00-\x7F]" file.txt; then
    echo "grep found something ..."
else
    echo "Nothing found!"
fi

Explicação💡:

  • -P, --perl-regexp: PATTERN é uma expressão regular do Perl
  • -o, --only-matching: mostra apenas a parte de uma linha correspondente a PATTERN
  • [^\x00-\x7F] é uma regex para corresponder a um único caractere não ASCII.
  • [[:ascii:]] - corresponde a um único caractere ASCII
  • [^[:ascii:]] - corresponde a um único caractere não ASCII

no bash

LC_COLLATE=C grep -o '[^ -~]' file
Toby Speight
fonte
3
Isso vai quebrar (ter um falso positivo) assim que alguém não fala Inglês ...
Kevin
ou se alguém tentar discutir à la carte, emoji, Pokémon ou qualquer outra coisa que não seja estritamente restrita ao ASCII de 7 bits. É melhor procurar qualquer coisa em 00-1F, exceto 09 0A 0D (guia, avanço de linha, retorno de carro).
Alcaro
Essa é uma péssima idéia. Isso rejeitará qualquer caractere Unicode válido acima do intervalo ASCII, apenas um pouco mais de um milhão de caracteres válidos. Surpreendente. Tente: printf '%b' "$(printf '\\U%x' {128..131})" | grep -oP "[^\x00-\x7F]"apenas 4 caracteres Unicode válidos que seu código rejeita. :-(
Isaac
Esta é uma resposta extremamente enganosa. Leia na minha resposta por que a abordagem simplista de limitar apenas ao ASCII falha muito.
Isaac