Как извлечь один фрагмент байтов из файла?

На рабочем столе Linux (RHEL4) я хочу извлечь диапазон байтов (обычно менее 1000) из большого файла (> 1 ГБ). Я знаю смещение в файле и размер чанка.

Я могу написать код для этого, но есть ли решение для командной строки?

В идеале что-то вроде:

magicprogram --offset 102567 --size 253 < input.binary > output.binary

person DanM    schedule 14.09.2009    source источник


Ответы (5)


Попробуйте dd:

dd skip=102567 count=253 if=input.binary of=output.binary bs=1
person Thomas Padron-McCarthy    schedule 14.09.2009
comment
При желании добавьте status=none для подавления вывода в stderr. - person kenorb; 06.10.2015
comment
Вот пример использования шестнадцатеричных смещений: dd if=in.bin bs=1 status=none skip=$((0x88)) count=$((0x80)) of=out.bin. - person kenorb; 06.10.2015
comment
@kenorb: я считаю, что шестнадцатеричный синтаксис является частью Bash, поэтому он не обязательно работает с другими оболочками. Я сам использую tcsh (не бейте меня!), и ваш пример там не работает. - person Thomas Padron-McCarthy; 06.10.2015
comment
Есть ли конкретная причина, по которой вы используете bs=1 и count=253, а не наоборот? Сделает ли больший размер блока команду более эффективной? - person rexford; 13.06.2017
comment
@rexford: Номер скипа тоже дается блоками, а не кратен 253. А учитывая, что ОС делает свою буферизацию при чтении из обычного файла в файловой системе, то в этом случае эффективность будет не такой базовой, как при чтении с устройства. - person Thomas Padron-McCarthy; 13.06.2017
comment
но я не хочу вычислять count, я знаю только начальное и конечное смещение. - person Jiang YD; 14.03.2019
comment
Не могли бы вы объяснить параметры? - person Lin Jian; 12.06.2020
comment
Однако bs=1 загружается медленнее, чем, скажем, bs=1000. Я действительно видел фактор 500 в коротком тесте. - person Stefan Reich; 05.08.2020

Это старый вопрос, но я хотел бы добавить еще одну версию команды dd, которая лучше подходит для больших фрагментов байтов:

dd if=input.binary of=output.binary skip=$offset count=$bytes iflag=skip_bytes,count_bytes 

где $offset и $bytes — числа в байтах.

Разница с принятым ответом Томаса заключается в том, что bs=1 здесь не появляется. bs=1 производит размер блока ввода и вывода равным 1 байту, что делает его ужасно медленным, когда количество байтов для извлечения велико.

person ChronoTrigger    schedule 24.11.2016
comment
Это действительно намного быстрее, чем мой ответ. - person Thomas Padron-McCarthy; 09.05.2018
comment
Не работает на Mac — iflag — неизвестный операнд, и без него вы получите целый блок. - person Timmmm; 14.05.2019
comment
@Timmmm GNU dd можно использовать для iflag поддержки (brew install coreutils). Примечание: по умолчанию утилиты устанавливаются с префиксом g (например, gdd вместо dd) - person Shakil; 16.05.2020
comment
идеальный трюк для ускорения, я собирался разделить файл размером 48 ГБ, и это спасло мне жизнь - person Ali Nadalizadeh; 18.12.2020

head -c + tail -c

Не уверен, как это сравнить с dd по эффективности, но это весело:

printf "123456789" | tail -c+2 | head -c3

выбирает 3 байта, начиная со второго:

234

См. также: https://stackoverflow.com/a/1272995/895245

person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 10.05.2017
comment
@elvis.dukaj да, другого быть не должно. Просто попробуйте с printf '\x01\x02' > f и hd. - person Ciro Santilli 新疆再教育营六四事件ۍ 23.07.2019
comment
Намного быстрее, чем dd с bs=1, спасибо! Обратите внимание, что tail считает байты с 1, а не с 0. Кроме того, tail завершает работу с кодом ошибки 1, когда его вывод преждевременно закрывается головкой. Обязательно игнорируйте эту ошибку при использовании set -e. - person proski; 25.08.2019

Все это может сделать команда dd. Посмотрите на параметры поиска и/или пропуска как часть вызова.

person Joe    schedule 14.09.2009

Даже быстрее

dd bs=<req len> count=1 skip=<req offset> if=input.binary of=output.binary 
person Albert Burbea    schedule 06.06.2019
comment
Проблема здесь в том, что skip находится в единицах bs. - person Arkku; 18.07.2019
comment
тем не менее, это должен быть ответ с наибольшим количеством голосов, тот, что выше с bs = 1, очень медленный: D - person Tchakabam; 10.05.2020
comment
это деталь для исполнителя, и все же лучше, чем выше, правда, вам нужно будет пересчитать, например: req_offset=$(bc <<< "$offset/$bs"), и убедиться, что получается круглое значение. - person Tchakabam; 10.05.2020