我有一个很大的二进制文件(几百 GB),我想从中提取一段。我知道起点和终点的十六进制字符串。
答案1
一种可能的解决方案(假设您可以复制文件)可以使用以下示例
- 假设起始模式为十六进制 4f 0f 87 82
- 假设结束模式为十六进制 fb 8c e2 a0
- 假设输入文件被调用
tf
且长度为 5000 字节
然后
将其复制tf
到一个新文件blah
,并改变起始模式
$ LC_ALL=C sed 's/'`printf "\x4f\x0f\x87\x82"`'/'`printf "AAAA"`'/' <tf > blah
tf
现在找到和不同的位置blah
(注意 - sed 在修改后的文件末尾写入一个包含换行符的额外字节,因此我们将其与原始文件的长度进行比较。tf
生成的文件blah
应该长一个字节)。
$ cmp -n 5000 -b tf blah
这将给出文件不同的字节偏移量 bs,例如,
tf blah differ: byte 4337, line 10 is 117 O 101 A
现在对结束模式做同样的事情
$ LC_ALL=C sed 's/'`printf "\xfb\x8c\xe2\xa0"`'/'`printf "AAAA"`'/' < tf > blah2
$ cmp -n 5000 -b tf blah2
tf blah2 differ: byte 4433, line 10 is 373 ? 101 A
现在用来dd
提取感兴趣的部分
dd if=tf skip=4336 bs=1 count=100 > fbit
一些额外的说明:
某些版本的 sed 支持
-b
将输入文件视为二进制的选项。其他版本则支持-z
用 NUL 字符分隔行的选项。无论匹配包含新行的模式还是拆分为新行,都尚未经过测试。这
count=100
将取决于匹配模式的长度以及匹配模式是否包含在提取物中(问题中没有明确说明)。一般公式是计数 = (结束偏移量) − (起始偏移量) + (结束模式的大小)。特定示例的片段为 4433-4337+1,共计 97 个字节。即从开始模式的开头到结束模式的第一个字节(包括第一个字节)。然后在此示例中添加额外的 3 个字节,共计 100 个字节,因为最终模式有四个字节,并且示例包含最终模式。如果不需要最终模式,则为count=96
值。可以使用一种对换行更稳健的方法,并使用 hexdump 命令。我还没有完全测试过这种方法。它本质上是使用 hexdump 和一些 sed、grep 和 tr 将原始二进制文件转换为 ASCII 格式的十六进制。然后可以应用相同的过程,但需要更复杂的算术等。所需的 hexdump 命令将是
hexdump -v -x tf | sed s/'^[0-9]*\(.*\)/\1/' | sed s'/ *//g' | grep '[0-9]' | tr -d '\n' > tf.txt
完成此步骤后,可以采用
hexdump
相同的过程。要匹配的模式必须更新为使用十六进制转储 ascii 字符,而不是原始十六进制打印。sed
cmp
这种方法还应该处理换行符。
LC_ALL=C
默认情况下,OSX 上似乎需要它。如果没有它,sed
命令会给出错误RE error: illegal byte sequence
。这可能不适用于所有平台和/或操作系统发行版。