Как сбросить часть двоичного файла

У меня есть двоичный файл и я хочу извлечь его часть, начиная с строки know byte (т. е. FF D8 FF D0) и заканчивая известной строкой byte (AF FF D9)

в прошлом я использовал dd чтобы вырезать часть двоичного файла из начала / конца, но эта команда, похоже, не поддерживает то, что я прошу.

какой инструмент на терминале можно это сделать?

6 ответов


в одной трубе:

xxd -c1 -p file |
  awk -v b="ffd8ffd0" -v e="aaffd9" '
    found == 1 {
      print 
      str = str 
      if (str == e) {found = 0; exit}
      if (length(str) == length(e)) str = substr(str, 3)}
    found == 0 {
      str = str 
      if (str == b) {found = 1; print str; str = ""}
      if (length(str) == length(b)) str = substr(str, 3)}
    END{ exit found }' |
  xxd -r -p > new_file
test ${PIPESTATUS[1]} -eq 0 || rm new_file

идея в том, чтобы использовать awk между xxd для выбора необходимой части файла. После того, как 1-й шаблон найден,awk выводит байт до 2-го паттерна и выход.

случай, когда 1-й шаблон найден, но 2-й не должен учитываться. Это делается в END часть awk скрипт, который возвращает ненулевой статус выхода. Это catch by bash ' s ${PIPESTATUS[1]} где я решил удалить новый файл.

обратите внимание, что пустой файл en также означает, что ничего не найдено.


найдите начальную / конечную позицию, затем извлеките диапазон.

$ xxd -g0 input.bin | grep -im1 FFD8FFD0  | awk -F: '{print }'
0000cb0
$ ^FFD8FFD0^AFFFD9^
0009590
$ dd ibs=1 count=$((0x9590-0xcb0+1)) skip=$((0xcb0)) if=input.bin of=output.bin

это должно работать со стандартными инструментами (xxd, tr, grep, awk, dd). Это правильно обрабатывает проблему "разбиение шаблона по линии", также ищите шаблон, выровненный только по смещению байта (не грызть).

file=<yourfile>
outfile=<youroutputfile>
startpattern="ff d8 ff d0"
endpattern="af ff d9"
xxd -g0 -c1 -ps ${file} | tr '\n' ' ' > ${file}.hex 
start=$((($(grep -bo "${startpattern}" ${file}.hex\
    | head -1 | awk -F: '{print }')-1)/3))
len=$((($(grep -bo "${endpattern}" ${file}.hex\
    | head -1 | awk -F: '{print }')-1)/3-${start}))
dd ibs=1 count=${len} skip=${start} if=${file} of=${outfile}

Примечание: скрипт выше использует временный файл, чтобы предотвратить двоичное > шестнадцатеричное преобразование дважды. Пространство/торговля-время передать результат xxd прямо в два grep. ОДН-вкладыш также возможен, за счет ясность.

можно использовать tee и именованный канал, чтобы предотвратить хранение временного файла и преобразование вывода дважды, но я не уверен, что это будет быстрее (xxd быстро) и, безусловно, сложнее писать.


посмотреть этой ссылке для способа сделать двоичный grep. После того, как у вас есть начальное и конечное смещение, вы должны иметь возможность с dd чтобы получить то, что вам нужно.


вариация на тему awk решение, которое предполагает, что ваш двоичный файл, преобразованный в hex с пробелами, помещается в память:

xxd -c1 -p file |
  tr "\n" " " |
  sed -n -e 's/.*\(ff d8 ff d0.*aa ff d9\).*//p' |
  xxd -r -p > new_file

другое решение в sed, но используя меньше памяти:

xxd -c1 -p file |
  sed -n -e '1{N;N;N}' -e '/ff\nd8\nff\nd0/{:begin;p;s/.*//;n;bbegin}' -e 'N;D' | 
  sed -n -e '1{N;N}' -e '/aa\nff\nd9/{p;Q1}' -e 'P;N;D' |
  xxd -r -p > new_file
test ${PIPESTATUS[2]} -eq 1 || rm new_file

1-й sed печать из ff d8 ff d0 до конца файла. Обратите внимание, что вам нужно столько N на -e '1{N;N;N}' как есть байты в вашем 1-м шаблоне меньше.

2-й sed печать с начала файла до aa ff d9. Еще раз обратите внимание, что вам нужно столько N на -e '1{N;N}' как есть байты в вашем 2-м шаблоне меньше один.

опять же, тест необходим, чтобы проверить, найден Ли 2-й шаблон, и удалить файл, если это не так.

отметим, что Q команда является расширением GNU для sed. Если у вас его нет, вам нужно выбросить остальную часть файла, как только шаблон будет найден (в цикле, таком как 1st sed, но не печать файла), и проверьте после преобразования hex в binary, что new_file заканчивается шаблоном Райта.