Esta é a solução de uma linha solicitada (para shells recentes que possuem "substituição de processo"):
grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l
Se nenhuma "substituição de processo" <(…)
estiver disponível, use grep como filtro:
hexdump -v -e '/1 "%02x "' infile.bin | grep -o "ef be ad de" | wc -l
Abaixo está a descrição detalhada de cada parte da solução.
Valores de bytes de números hexadecimais:
Seu primeiro problema é fácil de resolver:
Those \Xnn escape sequences only work in the fish shell.
Altere o% superiorX
para umx
inferior e use printf (para a maioria dos shells):
$ printf -- '\xef\xbe\xad\xde'
Ou use:
$ /usr/bin/printf -- '\xef\xbe\xad\xde'
Para as camadas que optam por não implementar a representação '\ x'.
É claro que traduzir hex para octal funcionará em (quase) qualquer shell:
$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'
Onde "$ sh" é qualquer shell (razoável). Mas é muito difícil mantê-lo corretamente citado.
Arquivos binários.
A solução mais robusta é transformar o arquivo e a seqüência de bytes (ambos) em alguma codificação que não tenha problemas com valores de caracteres ímpares como (nova linha) 0x0A
ou (byte nulo) 0x00
. Ambos são muito difíceis de gerenciar corretamente com ferramentas projetadas e adaptadas para processar "arquivos de texto".
Uma transformação como base64 pode parecer válida, mas apresenta a questão de que todo byte de entrada pode ter até três representações de saída, dependendo se é o primeiro, segundo ou terceiro byte da posição mod 24 (bits). / p>
$ echo "abc" | base64
YWJjCg==
$ echo "-abc" | base64
LWFiYwo=
$ echo "--abc" | base64
LS1hYmMK
$ echo "---abc" | base64 # Note that YWJj repeats.
LS0tYWJjCg==
Transformada hexadecimal.
É por isso que a transformação mais robusta deve ser aquela que inicia em cada limite de bytes, como a simples representação HEX.
Podemos obter um arquivo com a representação hexadecimal do arquivo com qualquer uma dessas ferramentas:
$ od -vAn -tx1 infile.bin | tr -d '\n' > infile.hex
$ hexdump -v -e '/1 "%02x "' infile.bin > infile.hex
$ xxd -c1 -p infile.bin | tr '\n' ' ' > infile.hex
A sequência de bytes a pesquisar já está em hexadecimal neste caso.
:
$ var="ef be ad de"
Mas também pode ser transformado. Um exemplo de um round-hex-bin-hex segue:
$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de
A cadeia de pesquisa pode ser definida a partir da representação binária. Qualquer uma das três opções apresentadas acima, hexdump ou xxd são equivalentes. Apenas certifique-se de incluir os espaços para garantir que a correspondência esteja nos limites de byte (sem desvio de nibble permitido):
$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de
Se o arquivo binário se parece com isto:
$ cat infile.bin | xxd
00000000: 5468 6973 2069 7320 efbe adde 2061 2074 This is .... a t
00000010: 6573 7420 0aef bead de0a 6f66 2069 6e70 est ......of inp
00000020: 7574 200a dead beef 0a66 726f 6d20 6120 ut ......from a
00000030: 6269 0a6e 6172 7920 6669 6c65 2e0a 3131 bi.nary file..11
00000040: 3232 3131 3232 3131 3232 3131 3232 3131 2211221122112211
00000050: 3232 3131 3232 3131 3232 3131 3232 3131 2211221122112211
00000060: 3232 0a
Em seguida, uma pesquisa grep simples fornecerá a lista de sequências correspondentes:
$ grep -o "$a" infile.hex | wc -l
2
Uma linha?
Tudo pode ser realizado em uma linha:
$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l
Por exemplo, a pesquisa por 11221122
no mesmo arquivo precisará dessas duas etapas:
$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4
Para "ver" as correspondências:
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
3131323231313232
3131323231313232
3131323231313232
3131323231313232
$ grep "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
… 0a 3131323231313232313132323131323231313232313132323131323231313232 313132320a
Buffer
Existe uma preocupação de que o grep armazene em buffer todo o arquivo e, se o arquivo for grande, crie uma carga pesada para o computador. Para isso, podemos usar uma solução sed não tamponada:
a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin |
sed -ue 's/\('"$a"'\)/\n\n/g' |
sed -n '/^'"$a"'$/p' |
wc -l
O primeiro sed é sem buffer ( -u
) e é usado apenas para injetar duas novas linhas no fluxo por string correspondente. O segundo sed
somente imprimirá as linhas (curtas) correspondentes. O wc -l contará as linhas correspondentes.
Isso armazenará apenas algumas linhas curtas. A (s) string (s) correspondente (s) no segundo sed. Isso deve ser bastante baixo em recursos usados.
Ou, um pouco mais complexo para entender, mas a mesma ideia em um só lugar:
a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin |
sed -u '/\n/P;//!s/'"$a"'/\n&\n/;D' |
wc -l