Як витягти один шматок байтів із файлу?


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, а не навпаки? Чи зробив би більший розмір блоку команду більш ефективною?
Рексфорд,

1
@rexford: Номер пропуску також подається блоками і не кратний 253. А враховуючи те, що ОС робить власну буферизацію при читанні із звичайного файлу у файловій системі, в цьому випадку ефективність буде не такою, як під час читання з пристрою.
Томас Падрон-Маккарті

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це невідомий операнд, і без нього ви отримуєте цілий блок.
Тімммм

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.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
Набагато швидше, ніж dd з bs = 1, дякую! Зверніть увагу, що хвіст підраховує байти від 1, а не від 0. Крім того, хвіст виходить із кодом помилки 1, коли його вихід передчасно закривається головою. Не забудьте проігнорувати цю помилку, використовуючи "set -e".
проскі

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
Чакабам,

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