Как захватить произвольный фрагмент из файла на 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
#