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


81

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

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

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

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

Ответы:


121

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

dd skip=102567 count=253 if=input.binary of=output.binary bs=1

2
Необязательно добавить, status=noneчтобы подавить вывод в stderr.
kenorb

13
Вот пример с использованием шестигранных смещения: dd if=in.bin bs=1 status=none skip=$((0x88)) count=$((0x80)) of=out.bin.
kenorb

@kenorb: я считаю, что шестнадцатеричный синтаксис является частью Bash, поэтому он не обязательно работает с другими оболочками. Я сам использую tcsh (не бейте меня!), И ваш пример там не работает.
Томас Падрон-Маккарти

1
Есть ли конкретная причина, по которой вы используете bs = 1 и count = 253, а не наоборот? Сделает ли больший размер блока команду более эффективной?
rexford

1
@rexford: номер пропуска также дается блоками и не кратен 253. И, учитывая, что ОС выполняет собственную буферизацию при чтении из обычного файла в файловой системе, в этом случае эффективность не будет такой низкой, как при чтении с устройства.
Thomas Padron-McCarthy

55

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

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

где $offsetи $bytes- числа в байтовых единицах.

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


4
Это действительно намного быстрее, чем мой ответ.
Томас Падрон-Маккарти

1
Не работает на Mac - iflagэто неизвестный операнд, и без него вы получите целый блок.
Timmmm

1
@Timmmm GNU ddможно использовать для iflagподдержки ( brew install coreutils). Примечание: по умолчанию утилиты устанавливаются с gпрефиксом (например, gddвместо dd)
Shakil

идеальный трюк для ускорения, я собирался разделить файл размером 48 ГБ, и это спасло мне жизнь
Али Надализаде

11

head -c + tail -c

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

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

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

234

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


@ elvis.dukaj да, по-другому быть не должно. Просто попробуйте printf '\x01\x02' > fи hd.
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

2
Намного быстрее, чем dd с bs = 1, спасибо! Обратите внимание, что tail подсчитывает байты от 1, а не от 0. Кроме того, tail завершается с кодом ошибки 1, когда его вывод преждевременно закрывается головкой. Обязательно игнорируйте эту ошибку при использовании "set -e".
proski

2

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


2

Даже быстрее

dd bs=<req len> count=1 skip=<req offset> if=input.binary of=output.binary 

2
Проблема здесь в том, что skipэто единицы bs.
Arkku

однако этот ответ должен быть самым популярным, ответ выше с bs = 1 очень медленный: D
Чакабам

это деталь для исполнителя, и все же лучше, чем выше, правда, вам нужно будет пересчитать, например: req_offset=$(bc <<< "$offset/$bs")и убедиться, что получается круглое значение.
Чакабам
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.