如果我有一个二进制文件,或者一些带有原始二进制输出的命令,并且我正在寻找一个 shell(bash)命令来裁剪数据的特定部分,即给定的开始和长度或结束偏移量(以字节为单位)。
例如,假设file.bin
包含abcdefghijk
,我会做类似的事情:
cat file.bin | crop 5 3
为了表明我只想保留偏移量为 5 且长度为 3 的部分,因此此示例将输出fgh
。
我知道有这个cut
命令,但它适用于文本内容并逐行处理输入。就我而言,我通常处理二进制数据,因此没有行的概念。我只是想以字节为单位指定要裁剪的部分。
有没有二进制替代品cut
?
答案1
POSIXtail
with-c
可以处理任意数据。不幸的是POSIXhead
不能。当仅限于 POSIX 时,您需要dd
;或者像这样:
<file.bin tail -c +6 | dd bs=1 count=3 2>/dev/null
或者像这样:
<file.bin dd bs=1 skip=5 count=3 2>/dev/null
bs=1
可能不是最优的,但即使你的skip=
和count=
可以重新计算为更大的bs=
,dd
仅使用 POSIX才bs=1
适合您。
GNUdd
支持iflag=fullblock
可能会在更大的情况下有所帮助bs=
。对于您使用 GNU 的情况,dd
更好的选择是iflag=skip_bytes,count_bytes
:
<file.bin dd iflag=skip_bytes,count_bytes skip=5 count=3 2>/dev/null
上述命令使用默认值bs=512
,尽管 5 和 3 都不是 512 的倍数,它仍能正常工作。此命令应该可以与任何合理的 一起使用bs=
。
如果如果您head
支持-c
计数字节,则在这种模式下读取时很可能不会等待整行。这导致了以下方法:
<file.bin tail -c +6 | head -c 3
可能还有其他解决方案。注意,如果command1
打印输入的前 5 个字节,然后command2
打印输入的前 3 个字节,那么
{ command1 >/dev/null; command2; } <file.bin
可能或者可能不会工作。一般来说 command1
可能会读更多的超过 5 个字节(并且仍然将 5 打印到其标准输出),因此当command2
开始读取时,指针可能位于错误的位置。我给您的命令不遵循这种可能有缺陷的模式。
答案2
dd
就可以了。如果您需要一个字节的粒度,则必须将块大小设置为 1:
cat file.bin | dd bs=1 skip=5 count=3