Рекурсивно искать каталог двоичных файлов для шестнадцатеричной последовательности?
Текущие команды, которые я использую для поиска некоторых шестнадцатеричных значений (скажем, 0A 8b 02
) привлекать:
find . -type f -not -name "*.png" -exec xxd -p {} \; | grep "0a8b02" || xargs -0 -P 4
Можно ли улучшить это с учетом следующих целей:
- поиск файлов рекурсивно
- отобразить смещение и имя файла
- исключить определенные файлы с определенными расширениями (приведенный выше пример не будет искать
.png
файлы) - скорость: поиск должен обрабатывать 200 000 файлов (от 50 КБ до 1 МБ) в общей сложности ~2 ГБ.
Я не слишком уверен, если xargs
работает нормально для 4 процессоров. Также у меня возникают проблемы с печатью имени файла, когда grep
находит совпадение, так как он по трубопроводу xxd
, Какие-либо предложения?
1 ответ
ЕСЛИ:
- у вас есть GNU
grep
- И шестнадцатеричные байты, которые вы ищете, НИКОГДА не содержат новых строк (
0xa
) [1]- Если они содержат NUL (
0x
), вы должны предоставитьgrep
поиск строки через файл (-f
) а не по прямому аргументу.
- Если они содержат NUL (
следующая команда приведет вас туда, используя пример поиска 0e 8b 02
:
LC_ALL=C find . -type f -not -name "*.png" -exec grep -FHoab $'\x{0e}\x{8b}\x{02}' {} + |
LC_ALL=C cut -d: -f1-2
grep
Команда производит выходные строки следующим образом:
<filename>:<byte-offset>:<matched-bytes>
который LC_ALL=C cut -d: -f1-2
затем сводится к <filename>:<byte-offset>
Команда почти работает с BSD grep
за исключением того, что сообщаемое смещение в байтах неизменно является началом строки, с которой был сопоставлен шаблон.
Другими словами: смещение байта будет корректным только в том случае, если в файле не будет ни одной новой строки.
Также BSD grep
не поддерживает указание NUL (0x0
) байт как часть строки поиска, даже если она предоставлена через файл с -f
,
- Обратите внимание, что параллельной обработки не будет, а только несколько
grep
вызовы, основанные на использованииfind
"s-exec ... +
, который, какxargs
, передает столько имен файлов, сколько поместится в командной строкеgrep
однажды. - Позволяя
grep
искать последовательность байтов напрямую, нет необходимостиxxd
:- Последовательность указана в виде строки ANSI C в кавычках, что означает, что escape-последовательности расширяются оболочкой до литералов, что позволяет Grep затем искать результирующую строку как литерал (через
-F
), что быстрее.
Связанная статья изbash
руководство, но они работают вzsh
(а такжеksh
) тоже.- Альтернативой GNU Grep является использование
-P
(поддержка PRCE, Perl-совместимых регулярных выражений) с нерасширенными escape-последовательностями, но это будет медленнее:grep -PHoab '\x{0e}\x{8b}\x{02}'
- Альтернативой GNU Grep является использование
LC_ALL=C
гарантирует, чтоgrep
обрабатывает каждый байт как свой собственный символ без применения каких-либо правил кодирования.-F
обрабатывает строки поиска как литерал (а не как регулярное выражение)-H
добавляет соответствующее имя входного файла к каждой строке вывода; обратите внимание, что Grep делает это неявно, если задано более 1 аргумента имени файла-o
сообщать только о совпадающих строках (байтовых последовательностях), а не о всей строке (в любом случае концепция строки не имеет смысла в двоичных файлах) [2]-a
обрабатывает двоичные файлы, как если бы они были текстовыми файлами (без этого Grep будет печатать только текстBinary file <filename> matches
для двоичных входных файлов с совпадениями)-b
сообщает о смещениях байтов совпадений
- Последовательность указана в виде строки ANSI C в кавычках, что означает, что escape-последовательности расширяются оболочкой до литералов, что позволяет Grep затем искать результирующую строку как литерал (через
Если в данном входном файле достаточно найти не более 1 совпадения, добавьте -m 1
,
[1] Новые строки нельзя использовать, потому что Grep неизменно обрабатывает новые строки в строке шаблона поиска как разделение нескольких шаблонов поиска. Кроме того, Grep основывается на строках, поэтому вы не можете найти совпадения между строками; GNU Grep's -null-data
может помочь опция разделения ввода на байты NUL, но только если ваша последовательность байтов поиска также не содержит байтов NUL; Вы также должны представить свои байтовые значения как escape-последовательности в регулярном выражении в сочетании с -P
- потому что вам нужно будет использовать escape-последовательность \n
вместо фактических новых строк.
[2] -o
необходимо сделать -b
сообщить смещение байтов совпадения в отличие от начала строки (как указано, BSD Grep всегда делает последнее, к сожалению); кроме того, здесь выгодно сообщать только о самих совпадениях, так как попытка напечатать всю строку приведет к непредсказуемо длинным выходным строкам, учитывая, что в двоичных файлах отсутствует понятие строк; в любом случае, вывод байтов из двоичного файла может вызвать странное поведение рендеринга в терминале.