如何以合理的速度复制二进制文件的任意部分?
显然,dd
withbs=1
非常慢,而设置bs
为另一个值则无法复制任意部分。
这是错的吗?可以用 做吗dd
?如果不是的话,那么工具是什么?
例如,这个命令,
dd if="$img" of=tail.bin bs=2147483648 skip=1 status=progress
复制错误的尾部。
这个命令
dd if="$img" of=tail.bin bs=1 skip=2147483648 status=progress
非常慢。
答案1
GNU dd 支持count_bytes
, seek_bytes
,skip_bytes
标志。这允许您使用具有任意偏移和大小的高性能块大小选择。
如果您指定字节单位,GNU dd 自版本 9.1 起默认执行此操作。
引用自coreutils/新闻:
如果块计数以“B”结尾,dd 现在计算字节而不是块。例如,“dd count=100KiB”现在复制 100 KiB 数据,而不是 102,400 个数据块。因此,标志 count_bytes、skip_bytes 和eek_bytes 已过时并且不再记录,尽管它们仍然有效。
另一种选择是创建具有所需偏移和尺寸限制的循环设备。这适用于本身不支持任意偏移的 dd (或任何其他程序)。
或者,您也可以考虑仅复制 bs=1 的部分第一个/最后一个块以及具有所需较大块大小的中间段。
答案2
尝试这个:
tail -c +$FROM file.dat | head -c $LENGTH > file1.dat
只需根据需要分配 FROM 和 LENGTH 即可。请注意, 的编号tail
是基于1 的,例如tail -c +4
表示从第四个字节开始,即跳过前三个字节。
举个例子:
$ printf 'abcdefghijklmnopqrstuvwxyz\n' > test.txt
$ tail -c +4 test.txt | head -c 6; echo
defghi
答案3
如果您希望文件的整个尾部从某个位置开始,一种方法是寻找文件描述符到正确的位置,然后使用cat
.使用 Perl 和 shell 重定向相对简单:
$ printf 'abcdefghijklmnopqrstuvwxyz\n' > test.txt
$ { perl -e 'sysseek STDIN, 23, 0'; cat; } < test.txt
xyz
或者使用通过环境传递的计数,以免与代码混淆:
$ { N=23 perl -e 'sysseek STDIN, $ENV{N}, 0'; cat; } < test.txt
xyz
一个子shell(perl; cat)
也可以工作。请注意,这是不是一个管道,只是perl
和cat
使用相同的打开文件描述。尽管请注意上面缺乏错误检查,但如果查找失败,它就不会发生。
要仅复制设定数量的字节,请使用管道 tohead -c
而不是cat
:
$ start=3 count=6
$ { N=$start perl -e 'sysseek STDIN, $ENV{N}, 0'; head -c $count; } < test.txt; echo
defghi