Как захватить произвольный фрагмент из файла на unix/linux
Я пытаюсь скопировать фрагмент из одного двоичного файла в новый файл. У меня есть смещение байта и длина фрагмента, который я хочу захватить.
Я попытался использовать утилиту dd
, но это, похоже, читает и отбрасывает данные до смещения, а не просто ищет (я думаю, потому что dd предназначен для копирования/преобразования блоков данных). Это делает его довольно медленным (и медленнее, чем выше смещение). Это команда, которую я пробовал:
dd if=inputfile ibs=1 skip=$offset count=$datalength of=outputfile
Думаю, я мог бы написать небольшой perl/python/whatever script, чтобы открыть файл, искать смещение, затем читать и записывать требуемый объем данных в кусках.
Есть ли утилита, которая поддерживает что-то вроде этого?
Ответы
Ответ 1
Да, неудобно делать это с помощью dd сегодня. Мы рассматриваем возможность добавления параметров skip_bytes и count_bytes в dd в coreutils. При этом должно работать следующее:
#!/bin/sh
bs=100000
infile=$1
skip=$2
length=$3
(
dd bs=1 skip=$skip count=0
dd bs=$bs count=$(($length / $bs))
dd bs=$(($length % $bs)) count=1
) < "$infile"
Ответ 2
Вы можете использовать tail -c+N
, чтобы обрезать ведущие N байтов от ввода, затем вы можете использовать head -cM
для вывода только первых M байтов из своего ввода.
$ echo "hello world 1234567890" | tail -c+9 | head -c6
rld 12
Таким образом, используя ваши переменные, это, вероятно, будет:
tail -c+$offset inputfile | head -c$datalength > outputfile
Ах, он не видел, что нужно искать. Оставляя это как CW.
Ответ 3
Спасибо за другие ответы. К сожалению, я не могу установить дополнительное программное обеспечение, поэтому опция ddrescue отсутствует. Решение голова/хвост интересно (я не понимал, что вы можете поставить + хвост), но сканирование через данные делает его довольно медленным.
В итоге я написал небольшой python script, чтобы делать то, что хотел. Размер буфера, вероятно, должен быть настроен так же, как и параметр внешнего буфера, но использование значения ниже достаточно для моей системы.
#!/usr/local/bin/python
import sys
BUFFER_SIZE = 100000
# Read args
if len(sys.argv) < 4:
print >> sys.stderr, "Usage: %s input_file start_pos length" % (sys.argv[0],)
sys.exit(1)
input_filename = sys.argv[1]
start_pos = int(sys.argv[2])
length = int(sys.argv[3])
# Open file and seek to start pos
input = open(sys.argv[1])
input.seek(start_pos)
# Read and write data in chunks
while length > 0:
# Read data
buffer = input.read(min(BUFFER_SIZE, length))
amount_read = len(buffer)
# Check for EOF
if not amount_read:
print >> sys.stderr, "Reached EOF, exiting..."
sys.exit(1)
# Write data
sys.stdout.write(buffer)
length -= amount_read
Ответ 4
Согласно man
dd
в FreeBSD:
skip=
n
Пропустите n блоков с начала ввода перед копированием. На входе, который поддерживает запросы, используется операция lseek (2). В противном случае входные данные считываются и отбрасываются. Для труб правильное количество байтов считывается. Для всех других устройств правильное количество блоков считывается без различия между частичный или полный считываемый блок.
Используя dtruss
, я подтвердил, что он использует lseek()
во входном файле в Mac OS X.
Если вы просто думаете, что это медленно, я согласен с комментарием, что это связано с размером блока размером в 1 байт.
Ответ 5
Вы можете использовать
--input-position=POS
ddrescue.
Ответ 6
Вы можете попробовать команду hexdump:
hexdump -v <File Path> -c -n <No of bytes to read> -s <Start Offset> | awk '{$1=""; print $0}' | sed 's/ //g'
Пример.) Прочтите 100 байтов из "mycorefile", начиная со смещения 100.
# hexdump -v -c mycorefile -n 100 -s 100 | awk '{$1=""; print $0}' | sed 's/ //g'
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\0\0\0\0001\0\0\0005\0\0\0\0020003\0
\0\0\0\0\0\[email protected]\0\0\0\0\0\0\0\0\0
\0\0\0\0\0\0\0\0\0\0\0\0\0 003\0
\0\0\0\0\0020\0\0\0\0\0\0001\0\0\0
006\0\0\0\0020003\0\0\0\0\0\0220c\0
\0\0\0\0
Затем, используя другой script, присоедините все строки вывода в одну строку, если хотите.
Если вы просто хотите увидеть содержимое:
# /usr/bin/hexdump -v -C mycorefile -n 100 -s 100
00000064 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000074 00 00 00 00 01 00 00 00 05 00 00 00 00 10 03 00 |................|
00000084 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 |[email protected]|
00000094 00 00 00 00 00 00 00 00 00 00 00 00 00 a0 03 00 |................|
000000a4 00 00 00 00 00 10 00 00 00 00 00 00 01 00 00 00 |................|
000000b4 06 00 00 00 00 10 03 00 00 00 00 00 00 90 63 00 |..............c.|
000000c4 00 00 00 00 |....|
000000c8
#