如何从unix / linux上的文件中获取任意块

时间:2009-08-13 15:21:41

标签: bash shell unix

我正在尝试将一个块从一个二进制文件复制到一个新文件中。我有字节偏移和我想要抓取的块的长度。

我尝试使用dd实用程序,但这似乎是读取并丢弃数据到偏移量,而不仅仅是寻找(我猜因为dd用于复制/转换数据块)。这使得它非常慢(偏移越高越慢。这是我尝试的命令:

dd if=inputfile ibs=1 skip=$offset count=$datalength of=outputfile

我想我可以编写一个小的perl / python /无论什么脚本来打开文件,寻找偏移量,然后以块的形式读取和写入所需数量的数据。

是否有支持此类内容的实用程序?

6 个答案:

答案 0 :(得分:13)

您可以使用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。

答案 1 :(得分:10)

是的,今天用dd做这件事很尴尬。我们正在考虑将core_tiltes和count_bytes参数添加到coreutils中的dd来提供帮助。以下应该可以工作:

#!/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 :(得分:1)

感谢其他答案。不幸的是,我无法安装其他软件,所以ddrescue选项已经出来了。头/尾解决方案很有意思(我没有意识到你可以提供+尾部),但扫描数据会使它变得很慢。

我最后编写了一个小python脚本来做我想做的事情。缓冲区大小应该调整为与某些外部缓冲区设置相同,但使用下面的值在我的系统上的性能足够。

#!/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

答案 3 :(得分:1)

根据man dd on FreeBSD

  

skip= n

     
    

在复制前从输入的开头跳过 n 块。     在支持搜索的输入上,使用lseek(2)操作。     否则,读取并丢弃输入数据。对于管道,     读取正确的字节数。对于所有其他设备,     读取正确的块数而不区分     正在读取部分或完整的块。

  

使用dtruss我确认它在Mac OS X上的输入文件中使用了lseek()。 如果您认为它很慢,那么我同意这可能是由于1字节块大小所致。

答案 4 :(得分:0)

您可以使用

--input-position=POS

选项ddrescue

答案 5 :(得分:0)

您可以尝试使用hexdump命令:

 hexdump  -v <File Path> -c -n <No of bytes to read> -s <Start Offset> | awk '{$1=""; print $0}' | sed 's/ //g'

例。)从&#39; mycorefile&#39;中读取100个字节。从抵消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\0@\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

然后,如果需要,使用另一个脚本将输出的所有行连接到单行。

如果您只想查看内容:

# /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  |......@.........|
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
#