Це запитується однолінійне рішення (для останніх оболонок, які мають "заміну процесу"):
grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l
Якщо "заміна процесу" <(…)
недоступна, просто використовуйте grep як фільтр:
hexdump -v -e '/1 "%02x "' infile.bin | grep -o "ef be ad de" | wc -l
Нижче наведено докладний опис кожної частини рішення.
Значення байтів із шістнадцяткових чисел:
Вашу першу проблему легко вирішити:
Ці послідовності втечі \ Xnn працюють лише в рибній оболонці.
Змініть верхній X
на нижній x
і використовуйте printf (для більшості оболонок):
$ printf -- '\xef\xbe\xad\xde'
Або скористайтеся:
$ /usr/bin/printf -- '\xef\xbe\xad\xde'
Для тих оболонок, які вирішили не реалізувати представлення '\ x'.
Звичайно, переклад шістнадцяткової на восьмеричну буде працювати на (майже) будь-якій оболонці:
$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'
Де "$ sh" - будь-яка (розумна) оболонка. Але це досить важко утримати правильно.
Бінарні файли.
Найбільш надійне рішення - перетворити файл і послідовність байтів (обидва) в якесь кодування, яке не має проблем із непарними значеннями символів, наприклад (новий рядок) 0x0A
або (нульовий байт) 0x00
. І те й інше досить складно правильно керувати інструментами, розробленими та адаптованими для обробки "текстових файлів".
Таке перетворення, як base64, може здатися допустимим, але воно задає питання про те, що кожен вхідний байт може мати до трьох вихідних представлень залежно, якщо це перший, другий або третій байт позиції mod 24 (біт).
$ echo "abc" | base64
YWJjCg==
$ echo "-abc" | base64
LWFiYwo=
$ echo "--abc" | base64
LS1hYmMK
$ echo "---abc" | base64 # Note that YWJj repeats.
LS0tYWJjCg==
Шестнадцяткова трансформація.
Ось чому найбільш надійна трансформація повинна бути такою, яка починається на кожній байтовій межі, як і просте HEX-представлення.
Ми можемо отримати файл із шестигранним представленням файлу будь-яким із цих інструментів:
$ 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
Послідовність байтів для пошуку вже в шістнадцятковій формі.
:
$ var="ef be ad de"
Але це також може бути перетворене. Приклад зворотної поїздки шестигранника:
$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de
Рядок пошуку може бути встановлений з двійкового подання. Будь-який із трьох варіантів, представлених вище, od, hexdump або xxd еквівалентні. Просто переконайтеся, що введіть пробіли, щоб переконатися, що відповідність знаходиться на байтових межах (заборонено зсув кулі):
$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de
Якщо двійковий файл виглядає приблизно так:
$ 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
Тоді простий греп-пошук надасть список відповідних послідовностей:
$ grep -o "$a" infile.hex | wc -l
2
Одна лінія?
Це все може виконуватися в один рядок:
$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l
Наприклад, для пошуку 11221122
в одному файлі знадобляться два кроки:
$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4
Щоб "побачити" сірники:
$ 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
Буферизація
Існує занепокоєння, що grep буде буферувати весь файл, і, якщо файл великий, створить велике навантаження для комп'ютера. Для цього ми можемо використовувати нерозподілений розчин sed:
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
Перший sed є нерозподіленим ( -u
) і використовується лише для введення двох нових рядків у потік за відповідний рядок. Друга sed
друкує лише (короткі) відповідні рядки. Wc -l буде рахувати відповідні лінії.
Це дозволить захистити лише деякі короткі рядки. Узгоджуючі рядок (и) у другій sed. Це має бути досить низьким у використанні ресурсів.
Або дещо складніше для розуміння, але однакова ідея в одному sed:
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