O que faz o grep considerar que um arquivo é binário?

170

Eu tenho alguns despejos de banco de dados de um sistema Windows na minha caixa. Eles são arquivos de texto. Estou usando o cygwin para passar por eles. Estes parecem ser arquivos de texto simples; Abro-os com editores de texto, como o bloco de notas e o wordpad, e eles parecem legíveis. No entanto, quando eu executo o grep, ele diz binary file foo.txt matches .

Tenho notado que os arquivos contêm alguns caracteres ascii NUL , que, acredito, são artefatos do dump do banco de dados.

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

    
por user394 01.09.2011 / 15:21

9 respostas

114

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

Pode haver uma solução como essa cat file | tr -d '%code%0' | yourgrep para eliminar todos os nulos primeiro e depois pesquisar por meio de arquivo.

    
por 01.09.2011 / 15:28
102

grep -a funcionou para mim:

$ grep --help
[...]
 -a, --text                equivalent to --binary-files=text
    
por 02.09.2015 / 11:43
20

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

    
por 26.11.2012 / 21:24
12

GNU grep 2.24 RTFS

Conclusão: apenas 2 e 2 casos:

  • NUL , por ex. printf 'ambrlen()' | grep 'a'

  • erro de codificação de acordo com o C99 \x80 , por exemplo:

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

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

Além disso, como mencionado por Stéphane Chazelas O que faz o grep considerar que um arquivo é binário? | Unix & Linux Stack Exchange , essas verificações só são feitas até a primeira leitura do buffer de comprimento TODO.

Somente até o primeiro buffer é lido

Portanto, se um erro NUL ou de codificação ocorrer no meio de um arquivo muito grande, ele poderá ser exibido de qualquer maneira.

Eu imagino que isso seja por motivos de desempenho.

Por exemplo: isto imprime a linha:

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

mas isso não acontece:

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 /src/grep.c , a primeira linha é passada para o grep, mesmo que tenha apenas 1 byte, 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

Encontre onde a mensagem de erro stderr está codificada:

git grep 'Binary file'

Leva-nos a encoding_error_output :

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

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

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

depois, apenas 0 <= nlines_first_null .

nlines_first_null e nlines

Inicializado como:

intmax_t nlines_first_null = -1;
nlines = 0;

então, quando um nulo for encontrado, nlines_first_null < nlines se tornará verdadeiro.

TODO quando %code% pode ser falso? Eu tenho preguiça.

POSIX

Não define opções binárias grep - procura um arquivo por um padrão | pubs.opengroup.org e o GNU grep não o documenta, portanto o RTFS é o único caminho.

    
por 12.04.2016 / 22:50
6

Um dos meus arquivos de texto foi subitamente visto como binário pelo 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
    
por 08.12.2014 / 22:30
5

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

Note que o binário pode ser apenas uma solução de fallback. À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

    
por 01.09.2011 / 15:27
2

Um dos meus alunos teve esse problema. Existe um erro em grep in Cygwin . Se o arquivo tiver caracteres não Ascii, grep e egrep o verão como binário.

    
por 10.09.2015 / 11:31
2

Na verdade, respondendo à pergunta "O que faz o grep considerar um arquivo como binário?", você pode usar iconv :

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

No meu caso, havia caracteres em espanhol que apareciam corretamente em editores de texto, mas grep os considerava como binários; iconv output me indicou os números de linha e coluna desses caracteres

No caso de NUL caracteres, iconv os considerará normais e não imprimirão esse tipo de saída, portanto, esse método não é adequado

    
por 20.05.2015 / 17:12
1

Eu tive o mesmo problema. Eu usei vi -b [filename] para ver os caracteres adicionados. Eu encontrei os caracteres de controle ^@ e ^M . Em seguida, 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 então em Ctrl + M ou Ctrl + @ . Em seguida, salve e saia do vi.

    
por 03.04.2015 / 20:58

Tags