Algumas vezes é necessário fazer buscas em arquivos binários. Há relativamente poucos tutoriais disponÃveis na Web sobre o tema, apesar das ferramentas disponÃveis no Linux oferecerem recursos para isso.
Este tutorial é escrito para apresentar esses recursos.
Visualização do arquivo com hexdump
O programa hexdump não está disponÃvel nas instalações padrão do Linux.
Assim, é preciso instalalá-lo. Em distribuições derivadas do Debian (como Ubuntu, Linux Mint etc.), isto pode ser feito com o familiar comando
apt install hexdump
A partir daÃ, uma apresentação muito conveniente é dada pela opção -C, que mostrará o conteúdo do arquivo em hexadecimal e ao lado, uma tentativade mostrá-lo em ASCII.
Vamos usar, nos exemplos a seguir, o conto Quem boa cama faz* de Machado de Assis, que é um pequeno arquivo PDF disponÃvel para ser baixado legal e gratuitamente em
https://dominiopublico.mec.gov.br/download/texto/ua000225.pdf
É um texto breve, de 19 páginas, com tamanho de apenas 64 kb.
Segue a apresentação das primeiras 10 linhas, obtidas com os comandos
hexdump -C ua000225.pdf | head
Neste caso o programa head mostra as 10 primeiras linhas da saÃda da execução de hexdump -C
A barra em pé | chamada de pipe ou "canalização", conecta a saÃda de hexdump -C com a entrada de head.
00000000 25 50 44 46 2d 31 2e 32 20 0d 0a 25 e2 e3 cf d3 |%PDF-1.2 ..%....|
00000010 0d 0a 20 0d 0a 38 20 30 20 6f 62 6a 0d 0a 3c 3c |.. ..8 0 obj..<<|
00000020 0d 0a 2f 4c 65 6e 67 74 68 20 39 20 30 20 52 0d |../Length 9 0 R.|
00000030 0a 2f 46 69 6c 74 65 72 20 2f 46 6c 61 74 65 44 |./Filter /FlateD|
00000040 65 63 6f 64 65 20 0d 0a 3e 3e 0d 0a 73 74 72 65 |ecode ..>>..stre|
00000050 61 6d 0d 0a 48 89 85 96 dd 6e 62 39 0c c7 9f 80 |am..H....nb9....|
00000060 77 c8 65 47 da 93 c6 76 3e 7b 35 14 a8 54 69 a7 |w.eG...v>{5..Ti.|
00000070 d3 d1 d2 3b 6e ce 00 dd 65 05 54 0b 6a 2b f5 e9 |...;n...e.T.j+..|
00000080 c7 49 ce a1 b4 98 1d 21 50 48 9c ff cf 71 e2 38 |.I.....!PH...q.8|
00000090 d7 d3 81 c5 a4 42 8c 1a 9d 52 d3 f1 c0 28 a3 9d |.....B...R...(..|
Os arquivos PDF possuem muitas informações codificadas em binário, mas também têm conteúdo em texto ASCII. Por exemplo, neste caso, o arquivo contém o texto /FlateDecode.
Outras informações podem ser obtidas paginando a execução de hexdump -C por mais linhas, usando, por exemplo, hexdump -C | less.
Busca com grep
Para buscar um padrão especÃfico em um arquivo, o comando grep é uma espécie canivete suÃço -- com múltiplas utilidades.
Uma busca simples em um arquivo de textos comum -- por exemplo, o código fonte de um programa --, a sintaxe de grep é trivial:
grep 'padrão'nome_do_arquivo
Para buscas em arquivos binários, outras opções são necessárias. Segue uma lista delas:
-aou--textfaz com quegrepignore marcações especiais no arquivo binário;-
-bou--byte-offsetfaz com quegrepmostre o deslocamento (ou offset) em bytes da cadeia de caracteres encontrada.Neste caso, offset significa que o primeiro byte é referidocomo
0, o segundo como1etc. -oou--only-matchingfaz com quegrepmostre apenas a cadeia de caracteres que atende os critérios de busca.
Para localizar a cadeia de caracteres Filter no arquivo ua000225.pdf aqui usado como exemplo, pode-se fazer
grep -a -b -o 'Filter' ua000225.pdf
Como sabemos que há muitas ocorrências da palavra Filter neste pequeno arquivo, vamos restringir sua busca por apenas 1 ocorrência, usando novamente o utilitário head:
grep -a -b -o 'Filter' ua000225.pdf | head -1
Isto gerará a saÃda:
50:Filter
Isto significa que a palavra Filter começa a partir da posição 51 do
arquivo ua000225.pdf O que, segundo alguns, é uma boa ideia.
Expressões regulares
Para aumentar ainda mais o poder do grep há o recurso das
expressões regulares
Esse recurso é muito poderoso e pode até mesmo se tornar complexo. Aqui, usaremos apenas o mÃnimo delas.
Para usar expressões regulares com o grep pode-se usar a opção -E ou --extended-regexp, que permite certas simplificações.
Por exemplo, para encontrar todas palavras iniciadas por uma letra maiúscula e seguidas por pelo menos uma letra minúscula, usa-se como expressão de busca o texto [A-Z][a-z]\+
As expressões [A-Z] e [a-z] indicam classes de caracteres. No caso, respectivamente todas as letras maiúsculas e todas as letras minúsculas. O sinal + indica que o caractere anterior deve aparecer pelo menos uma vez, sem limite de repetições.
O caracter + é prefixado por uma contrabarra, ou \ para distinguir essa repetição da busca do caracter +.
Então, neste caso, o comando se torna:
grep -a -b -o '[A-Z][a-z]\+' ua000225.pdf
Então, surgem 1088 linhas. Para restringir a busca a apenas 10 linhas, usamos novamente head:
grep -a -b -o '[A-Z][a-z]\+' ua000225.pdf | head
O que gera:
35:Length
50:Filter
58:Flate
63:Decode
109:Ti
160:Ae
279:Tc
283:Kpj
292:Hu
340:RÉ¢
As cadeias de caracteres muito curtas (como Ti ou Ae) possivelmente são combinações aleatórias de valores binários. É possÃvel exigir comprimentos mÃnimos maiores de resultados de busca. Uma das formas é usar as chaves.
Uma curiosidade é que quando se usa + em vez de +, o resultado é
diferente. Ou seja: os comandos
grep -a -b -o '[A-Z][a-z]+' ua000225.pdf
geram
12090:Yk+
24288:Ld+
A breve visualização do arquivo mostrou que as palavras maiores são
precedidas por uma barra /. Assim, pode-se alterar a expressão de busca para
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf
Isto gerará 428 ocorrências no arquivo em uso. Para restringi-las, usa-se
novamente o head:
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | head
E finalmente,
34:/Length
49:/Filter
57:/Flate
339:/RÉ¢
992:/Type
1008:/Subtype
1017:/Image
1025:/Name
1037:/Filter
1058:/Width
Separação de campos
Para usar os resultados das buscas, pode-se aplicar o utilitário padrão awk, que permite separar o offset da cadeia de caracteres.
Por exemplo, para extrair apenas a cadeia de caracteres:
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | awk -F ':' '{ print $2 }'
Para apresentar apenas as primeiras linhas, usa-se de novo head:
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | awk -F ':' '{ print $2 }' | head
O que gera:
/Length
/Filter
/Flate
/RÉ¢
/Type
/Subtype
/Image
/Name
/Filter
/Width
Ou para extrair apenas o offset:
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | awk -F ':' '{ print $1 }' | head
Com o resultado:
34
49
57
992
1008
1017
1025
1037
1058
1070
Pelos exemplos, não é tão difÃcil ver que o comando awk está permitindo separar os elementos da saÃda de grep. A opção -F ':'' define o caracter de separação entre os dois campos, que é :'.
A forma $1 define o primeiro campo (o offset) e a forma $2 define o
segundo campo, que é a cadeia de caracteres encontrada.
Contagem de ocorrências
Para contar quantas vezes uma determinada string aparece, podem-se suar dois comandos, sort e uniq.
O comando sort (literalmente "classificação") ordena a saÃda de grep. Assim, a linha
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | awk -F ':' '{ print $2 }' | sort | head
vai mostrar
/Amer
/Amer
/Arial
/Arial
/Arial
/Arial
/Ascent
/Ascent
/Ascent
/Ascent
O que permite contar que /Amer occore 2 vezes e /Arial ocorre 4 vezes.
Para contar todas as ocorrências, usa-se uniq -c. Assim, a linha
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | awk -F ':' '{ print $2 }' | sort | uniq -c | head
mostra
2 /Amer
4 /Arial
6 /Ascent
6 /Avg
6 /Base
2 /Batang
1 /Bi
1 /Bits
2 /Cal
6 /Cap
Caso não se queira a contagem, deixa-se de lado o -c do uniq.
Assim, a linha
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | awk -F ':' '{ print $2 }' | sort | uniq | head
agora mostra
/Amer
/Arial
/Ascent
/Avg
/Base
/Batang
/Bi
/Bits
/Cal
/Cap
Por último, para se saber quais são as cadeias de caracteres mais comuns,faz-se
grep -a -b -o '/[A-Z][a-z]\+' ua000225.pdf | awk -F ':' '{ print $2 }' | sort | uniq -c | sort -r -n | head
O que gera
49 /Font
38 /Type
23 /Parent
21 /Length
21 /Filter
20 /Flate
19 /Resources
19 /Proc
19 /Page
19 /Contents
A opção -r de sort faz com que a ordenação seja decrescente: do mais frequente para o menos frequente. A opção -n faz com que o primeiro campo da saÃda seja interpretado como um número.














