Tenho alguns despejos de banco de dados de um sistema Windows em minha caixa. Eles são arquivos de texto. Estou usando o cygwin para fazer o grep por meio deles. Eles parecem ser arquivos de texto simples; eu os abro com editores de texto como notepad e wordpad e eles parecem legíveis. No entanto, quando eu executar o grep neles, ele mostrará binary file foo.txt matches.

Percebi que os arquivos contêm alguns caracteres ascii NUL, que acredito serem artefatos do despejo do banco de dados.

Então, o que faz o grep considerar esses arquivos binários? O caractere NUL? Existe um sinalizador no sistema de arquivos? O que preciso mudar para colocar o grep mostrar as correspondências de linha?

Comentários

  • --null-data podem ser úteis se NUL é o delimitador.

Resposta

Se houver um NUL caractere em qualquer lugar no arquivo, grep irá considerá-lo como um arquivo binário.

Pode haver uma solução alternativa como esta cat file | tr -d "\000" | yourgrep para eliminar todos nulos primeiro, e em seguida, para pesquisar no arquivo.

Comentários

  • … ou use -a / --text, pelo menos com GNU grep.
  • @derobert: na verdade, em alguns sistemas (mais antigos), grep vê as linhas, mas sua saída truncará cada linha correspondente no primeiro NUL (provavelmente porque chama C ‘ s printf e fornece a linha correspondente?). Nesse sistema, um grep cmd .sh_history retornará tantas linhas vazias quantas forem as linhas correspondentes a ‘ cmd ‘, pois cada linha de sh_history tem um formato específico com um NUL no início de cada linha. (mas seu comentário ” pelo menos no GNU grep ” provavelmente se concretizou. Eu não ‘ não tenho um disponível agora para testar, mas espero que eles lidem bem com isso)
  • A presença de um caractere NUL é o único critério? Eu duvido. É ‘ provavelmente mais inteligente do que isso. Qualquer coisa fora do intervalo Ascii 32-126 seria o meu palpite, mas ‘ teríamos que olhar o código-fonte para ter certeza.
  • Minhas informações eram na página de manual da instância grep específica. Seu comentário sobre a implementação é válido, a fonte supera os documentos.
  • Eu tinha um arquivo que grep no cygwin era considerado binário porque tinha um traço longo (0x96) em vez de um hífen / menos ASCII regular (0x2d). Acho que esta resposta resolveu o problema do OP ‘ s, mas parece que está incompleto.

Resposta

grep -a funcionou para mim:

$ grep --help [...] -a, --text equivalent to --binary-files=text 

Comentários

  • Esta é a melhor e menos cara resposta IMO.
  • Mas não compatível com POSIX
  • Você se importaria de explicar por que não é? Seria bom deixar isso claro, para todos nós que encontramos essa resposta como uma opção. Obrigado :).
  • Ei, ‘ vim aqui uma SEGUNDA vez para reaprender este LOL. Um sotaque francês (diacrítico) no texto estava causando grep para barf

Resposta

Você pode usar o strings utilitário para extrair o conteúdo de texto de qualquer arquivo e, em seguida, canalizá-lo por meio de grep, assim: strings file | grep pattern.

Comentários

  • Ideal para grepping arquivos de log que podem estar parcialmente corrompidos
  • sim, às vezes, log binário misto também acontece. Isso é bom.

Resposta

GNU grep 2.24 RTFS

Conclusão: 2 e 2 casos apenas:

  • NUL, por exemplo printf "a\0" | grep "a"

  • Erro de codificação de acordo com o C99 mbrlen(), por exemplo:

    export LC_CTYPE="en_US.UTF-8" printf "a\x80" | grep "a" 

    porque \x80 não pode ser o primeiro byte de um ponto Unicode UTF-8: UTF-8 – Descrição | en.wikipedia.org

Além disso, conforme mencionado por Stéphane Chazelas O que faz o grep considerar um arquivo para ser binário? | Unix & Linux Stack Exchange , essas verificações são feitas apenas até o primeiro buffer lido de comprimento TODO.

Somente até o primeiro buffer ler

Portanto, se um NUL ou erro de codificação acontecer no meio de um arquivo muito grande, pode ser grepped de qualquer maneira.

Imagino que seja por motivos de desempenho.

Por exemplo: isso imprime a linha:

printf "%10000000s\n\x80a" | grep "a" 

mas isso não:

printf "%10s\n\x80a" | grep "a" 

O tamanho real do buffer depende de como o arquivo é lido. Por exemplo.compare:

export LC_CTYPE="en_US.UTF-8" (printf "\n\x80a") | grep "a" (printf "\n"; sleep 1; printf "\x80a") | grep "a" 

Com o sleep, a primeira linha é passada para grep, mesmo que seja apenas 1 byte longo porque o processo entra em suspensão e a segunda leitura não verifica se o arquivo é binário.

RTFS

git clone git://git.savannah.gnu.org/grep.git cd grep git checkout v2.24 

Descubra onde a mensagem de erro stderr está codificada:

git grep "Binary file" 

Nos leva a /src/grep.c:

if (!out_quiet && (encoding_error_output || (0 <= nlines_first_null && nlines_first_null < nlines))) { printf (_("Binary file %s matches\n"), filename); 

Se essas variáveis fossem bem nomeadas, basicamente chegamos à conclusão.

encoding_error_output

Quick grepping para encoding_error_output mostra que o único caminho de código que pode modificá-lo passa por buf_has_encoding_errors:

clen = mbrlen (p, buf + size - p, &mbs); if ((size_t) -2 <= clen) return true; 

e apenas man mbrlen.

nlines_first_null e nlines

Inicializado como:

intmax_t nlines_first_null = -1; nlines = 0; 

então, quando um nulo é encontrado, 0 <= nlines_first_null torna-se verdadeiro.

TODO quando pode nlines_first_null < nlines nunca será falso? Eu fiquei com preguiça.

POSIX

Não define opções binárias grep – pesquisa um arquivo para um padrão | pubs.opengroup.org , e GNU grep não documenta, então RTFS é a única maneira.

Comentários

  • Explicação impressionante !
  • Observe que a verificação de UTF-8 válido ocorre apenas em locales UTF-8. Observe também que a verificação é feita apenas no primeiro buffer lido do arquivo, que para um arquivo normal parece ter 32768 bytes no meu sistema, mas para um pipe ou socket pode ser tão pequeno quanto um byte. Compare (printf '\n\0y') | grep y com (printf '\n'; sleep 1; printf '\0y') | grep y por exemplo.
  • @St é phaneChazelas ” Observe que a verificação de UTF-8 válido ocorre apenas em localidades UTF-8 “: você quer dizer sobre o export LC_CTYPE='en_US.UTF-8' como no meu exemplo, ou algo mais? Buf read: exemplo incrível, adicionado à resposta. Obviamente, você leu a fonte mais do que eu, lembra-me daqueles hacker koans ” O aluno foi esclarecido ” 🙂
  • Eu não ‘ também analisei os detalhes, mas fez recentemente
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 com qual versão do GNU grep você testou?

Resposta

Um dos meus arquivos de texto de repente foi visto como binário por grep:

$ file foo.txt foo.txt: ISO-8859 text 

A solução foi convertê-lo usando iconv:

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt 

Comentários

  • Isso aconteceu comigo também. Em particular, a causa foi um espaço sem quebra com codificação ISO-8859-1, que tive que substituir por um espaço regular para fazer o grep pesquisar no arquivo.
  • grep 2.21 trata ISO -8859 arquivos de texto como se fossem binários, adicione export LC_ALL = C antes do comando grep.
  • @netawater Obrigado! Este é, por exemplo o caso se você tiver algo como M ü ller em um arquivo de texto. Aquele ‘ s 0xFC hexadecimal, portanto, fora do intervalo, grep esperaria para utf8 (até 0x7F). Verifique com printf ‘ a \ x7F ‘ | grep ‘ a ‘ como Ciro descreveu acima.

Resposta

O arquivo /etc/magic ou /usr/share/misc/magic tem uma lista de sequências que o comando file usa para determinar o tipo de arquivo.

Observe que o binário pode ser apenas uma solução alternativa. Às vezes, arquivos com codificação estranha também são considerados binários.

grep no Linux tem algumas opções para lidar com arquivos binários como --binary-files ou -U / --binary

Comentários

Resposta

Um dos meus alunos teve este problema. Há um bug em grep em Cygwin. Se o arquivo tiver caracteres não ASCII, grep e egrep veja-o como binário.

Comentários

  • Isso parece um recurso, não um bug.Especialmente porque há uma opção de linha de comando para controlá-lo (-a / –text)

Resposta

Respondendo à pergunta “O que faz o grep considerar um arquivo binário?”, Você pode usar iconv:

$ iconv < myfile.java iconv: (stdin):267:70: cannot convert 

No meu caso, havia caracteres espanhóis que apareciam corretamente nos editores de texto, mas o grep os considerava binários; iconv a saída apontou-me para os números de linha e coluna desses caracteres

No caso de NUL caracteres, iconv irá considerá-los normais e não imprimirá esse tipo de saída, então este método não é adequado

Resposta

Eu tive o mesmo problema. Usei vi -b [filename] para ver os caracteres adicionados. Encontrei os caracteres de controle ^@ e ^M. Então, no vi, digite :1,$s/^@//g para remover os ^@ caracteres. Repita este comando para ^M.

Aviso: para obter os caracteres de controle “azuis”, pressione Ctrl + v e, em seguida, Ctrl + M ou Ctrl + @ . Em seguida, salve e saia do vi.

Resposta

Eu também tive este problema, mas no meu caso foi causado quando uma linha correspondente é muito longo.

file myfile.txt myfile.txt: UTF-8 Unicode text, with very long lines 

grep seria executado em todo o arquivo bem com muitos padrões, mas quando um padrão correspondeu a um ” linha muito longa ” parou com Binary file myfile.txt matches.

Adicionar -a também resolve esse problema, mas pré-analisar o arquivo para NULL ou outros caracteres inválidos não teria efeito (não há nenhum, caso contrário, o grep não seria concluído para outros padrões). Neste caso, a linha incorreta tinha 25k + caracteres!

O que eu não entendo é por que isso só acontece quando grep tenta retornar a linha e não quando ela está processando em busca de outros padrões.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *