Dies ist die angeforderte Ein-Liner-Lösung (für aktuelle Shells mit "Prozesssubstitution"):
grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l
Wenn keine "Prozessersetzung" <(…)
verfügbar ist, verwenden Sie einfach grep als Filter:
hexdump -v -e '/1 "%02x "' infile.bin | grep -o "ef be ad de" | wc -l
Nachstehend finden Sie eine detaillierte Beschreibung der einzelnen Teile der Lösung.
Byte-Werte aus Hex-Zahlen:
Ihr erstes Problem ist leicht zu lösen:
Diese \ Xnn-Escape-Sequenzen funktionieren nur in der Fischhülle.
Ändern Sie die obere X
in eine untere x
und verwenden Sie printf (für die meisten Shells):
$ printf -- '\xef\xbe\xad\xde'
Oder benutze:
$ /usr/bin/printf -- '\xef\xbe\xad\xde'
Für diejenigen Shells, die die Darstellung '\ x' nicht implementieren möchten.
Natürlich funktioniert die Übersetzung von Hex nach Oktal auf (fast) jeder Shell:
$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'
Wobei "$ sh" eine beliebige (vernünftige) Shell ist. Aber es ist ziemlich schwierig, es richtig zu zitieren.
Binärdateien.
Die robusteste Lösung besteht darin, die Datei und die Bytefolge (beide) in eine Codierung umzuwandeln, die keine Probleme mit ungeraden Zeichenwerten wie (neue Zeile) 0x0A
oder (Null-Byte) aufweist 0x00
. Beide sind mit Tools, die für die Verarbeitung von "Textdateien" entwickelt und angepasst wurden, nur schwer korrekt zu verwalten.
Eine Transformation wie base64 mag als gültig erscheinen, birgt jedoch das Problem, dass jedes Eingabebyte bis zu drei Ausgabedarstellungen haben kann, je nachdem, ob es sich um das erste, zweite oder dritte Byte der Mod-24-Position (Bits) handelt.
$ echo "abc" | base64
YWJjCg==
$ echo "-abc" | base64
LWFiYwo=
$ echo "--abc" | base64
LS1hYmMK
$ echo "---abc" | base64 # Note that YWJj repeats.
LS0tYWJjCg==
Verhexung transformieren.
Deshalb sollte die robusteste Transformation eine sein, die an jeder Byte-Grenze beginnt, wie die einfache HEX-Darstellung.
Wir können eine Datei mit der hexadezimalen Darstellung der Datei mit jedem dieser Tools erhalten:
$ 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
Die zu durchsuchende Bytefolge ist in diesem Fall bereits hexadezimal.
:
$ var="ef be ad de"
Es könnte aber auch transformiert werden. Ein Beispiel für eine Rundreise hex-bin-hex folgt:
$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de
Der Suchstring kann aus der Binärdarstellung gesetzt werden. Alle drei oben aufgeführten Optionen od, hexdump oder xxd sind gleichwertig. Stellen Sie einfach sicher, dass die Leerzeichen enthalten sind, um sicherzustellen, dass die Übereinstimmung an den Byte-Grenzen liegt (keine Nibble-Verschiebung zulässig):
$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de
Wenn die Binärdatei so aussieht:
$ 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
Dann gibt eine einfache Suche nach grep die Liste der übereinstimmenden Sequenzen aus:
$ grep -o "$a" infile.hex | wc -l
2
Eine Linie?
Es kann alles in einer Zeile ausgeführt werden:
$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l
Für die Suche 11221122
in derselben Datei sind beispielsweise die folgenden zwei Schritte erforderlich:
$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4
So "sehen" Sie die Übereinstimmungen:
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
3131323231313232
3131323231313232
3131323231313232
3131323231313232
$ grep "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
… 0a 31313232313132323131323231313232313132323131323131323231313232 313132320a
Pufferung
Es besteht die Sorge, dass grep die gesamte Datei puffert und, wenn die Datei groß ist, eine hohe Last für den Computer erstellt. Dafür können wir eine ungepufferte sed-Lösung verwenden:
a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin |
sed -ue 's/\('"$a"'\)/\n\1\n/g' |
sed -n '/^'"$a"'$/p' |
wc -l
Die erste sed ist ungepuffert ( -u
) und wird nur zum Einfügen von zwei Zeilenumbrüchen in den Stream pro übereinstimmender Zeichenfolge verwendet. Die Sekunde sed
wird nur die (kurzen) übereinstimmenden Zeilen drucken. Das wc -l zählt die übereinstimmenden Zeilen.
Dies puffert nur einige kurze Zeilen. Die passende (n) Saite (n) im zweiten Satz. Dies sollte relativ ressourcenschonend sein.
Oder etwas komplexer zu verstehen, aber die gleiche Idee in einem Satz:
a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin |
sed -u '/\n/P;//!s/'"$a"'/\n&\n/;D' |
wc -l
grep -o