Я хочу получить байтовое смещение шаблона строки из двоичного файла на встроенной платформе Linux.
Если бы я мог использовать опцию «grep -b», это было бы лучшим способом, но она не поддерживается на моей машине.
Машина не поддерживает
ADDR=`grep -oba <pattern string> <file path> | cut -d ":" -f1`
Вот руководство по команде grep на машине.
root# grep --help
BusyBox v1.29.3 () multi-call binary.
Usage: grep \[-HhnlLoqvsriwFE\] \[-m N\] \[-A/B/C N\] PATTERN/-e PATTERN.../-f FILE \[FILE\]...
Search for PATTERN in FILEs (or stdin)
-H Add 'filename:' prefix
-h Do not add 'filename:' prefix
-n Add 'line_no:' prefix
-l Show only names of files that match
-L Show only names of files that don't match
-c Show only count of matching lines
-o Show only the matching part of line
-q Quiet. Return 0 if PATTERN is found, 1 otherwise
-v Select non-matching lines
-s Suppress open and read errors
-r Recurse
-i Ignore case
-w Match whole words only
-x Match whole lines only
-F PATTERN is a literal (not regexp)
-E PATTERN is an extended regexp
-m N Match up to N times per file
-A N Print N lines of trailing context
-B N Print N lines of leading context
-C N Same as '-A N -B N'
-e PTRN Pattern to match
-f FILE Read pattern from file
Так как этот вариант недоступен, я ищу альтернативу.
Комбинация hexdump и grep также может быть полезна
Такие как
ADDR=`hexdump <file path> -C | grep <pattern string> | cut -d' ' -f1`
Но если pattren занимает несколько строк, он не будет найден.
Есть ли способ найти смещение в байтах определенного шаблона с помощью команды Linux?
Что-то вроде этого?
hexdump -C "$file" |
awk -v pattern = "$pattern" 'residue { matched = ($0 ~ "\\|" residue)
if (matched) print $1; residue = ""; if (matched) next }
$0 ~ pattern { print $1 }
{ for(i=length(pattern)-1; i>0; i--)
if ($0 ~ substr(pattern, 1, i) "\\|$") { residue=substr(pattern, i+1); break } }'
Смещение — это только первое поле из вывода hexdump; если вам нужно точное местоположение совпадения, это требует дополнительного массажа, чтобы выяснить смещение, которое нужно добавить к адресу, или вычесть, если оно было завернуто.
Кратко протестировано в чистом контейнере Busybox Docker, где вывод hexdump -C выглядит следующим образом:
/ # hexdump -C /etc/resolv.conf
00000000 23 20 44 4e 53 20 72 65 71 75 65 73 74 73 20 61 |# DNS requests a|
00000010 72 65 20 66 6f 72 77 61 72 64 65 64 20 74 6f 20 |re forwarded to |
00000020 74 68 65 20 68 6f 73 74 2e 20 44 48 43 50 20 44 |the host. DHCP D|
00000030 4e 53 20 6f 70 74 69 6f 6e 73 20 61 72 65 20 69 |NS options are i|
00000040 67 6e 6f 72 65 64 2e 0a 6e 61 6d 65 73 65 72 76 |gnored..nameserv|
00000050 65 72 20 31 39 32 2e 31 36 38 2e 36 35 2e 35 0a |er 192.168.65.5.|
00000060 20 | |
Пожалуйста, но, пожалуйста, не оставляйте комментарии «спасибо». Если вам что-то нравится, проголосуйте за это.
Установите шаблон в качестве разделителя записей в awk. Смещение вхождения равно длине первой записи. BusyBox awk обрабатывает RS как расширенное регулярное выражение, поэтому добавьте обратную косую черту перед любым из .[]\*+?^$ в строке шаблона.
<myfile.bin awk -v RS='pattern' '{print length($0); exit}'
Если шаблон содержит нулевой байт, вам потребуется немного дополнительной работы. Используйте tr для замены нулевых байтов некоторым значением байта, которое не отображается в шаблоне. Например, если шестнадцатеричный дамп шаблона равен 00002a61:
<myfile.bin tr '\0!' '!\0' | awk -v RS='!!-A' '{print length($0); exit}'
Если шаблон не найден, печатается длина всего файла. Поэтому, если вы не уверены, присутствует ли шаблон, вам снова потребуется дополнительная работа. Добавьте к файлу некоторый текст, который не может быть частью совпадения с шаблоном, чтобы вы знали, что если совпадение есть, оно не будет в самом конце файла. Тогда, если шаблон присутствует, файл будет содержать как минимум две записи. Но если шаблона нет, файл содержит только первую запись (без разделителя записей после нее).
{ cat myfile.bin; echo garbage; } |
awk -v RS='pattern' '
NR==1 {n = length($0)}
NR==2 {print n; found = 1; exit}
END {exit !found}
'
Кроме того, вероятно, избегайте верхнего регистра для имен ваших частных переменных и предпочитайте современный $(command substitution) синтаксис устаревшим обратным кавычкам.