您如何对 dd 进行精细控制?

您如何对 dd 进行精细控制?

我有一张 64GB 的 MicroSD 卡。我向其中写入了一个大小为 16GB 的图像:

$ sudo dd if=my_image.img of=/dev/sdb bs=4M
3798+1 records in
3798+1 records out
15931539456 bytes (16 GB, 15 GiB) copied, 657.848 s, 24.2 MB/s

现在,我想使用 dd 拍摄同一张 64GB SD 卡的前 15931539456 字节 (16GB) 的图像,最终得到一个与我开始使用的图像具有相同校验和的图像。

据我了解,上面 dd 的结果(3798+1)表明,从源图像中有 3798 个完整读取,以及 1 个部分读取,因为源图像的大小没有均匀地分割成 4M 块。那么我如何告诉 dd 现在将 15931539456 字节从 SD 卡复制到一个新文件中,一次 4M?

我假设我可以做类似的事情:

sudo dd if=/dev/sdb of=new_image.img bs=1 count=15931539456

但缓冲区这么小会使操作永远持续下去。有没有办法告诉它使用 4M 的缓冲区,但只复制 X 个字节,即使这会导致最后的读取很短?

答案1

几种可能性:

  1. 使用更小的bs,但不是很小:

    dd if=/dev/sdb of=new_image.img bs=512k count=30387
    

    这不是一个通用的解决方案。它在这里起作用是因为15931539456可以因式分解。

  2. 使用您想要的bs,阅读更多内容并即时截断:

    dd if=/dev/sdb bs=4M | head -c 15931539456 >new_image.img
    

    你不需要count=3799这里。好吧,你甚至不需要dd

     head -c 15931539456 /dev/sdb >new_image.img
    

    我希望head能够阅读理智的内容并表现良好。head -cPOSIX 不需要注释。

  3. 使用您想要的bs,阅读更多内容并稍后截断:

    dd if=/dev/sdb of=new_image.img bs=4M count=3799
     truncate -s 15931539456 new_image.img
    

    truncate虽然不便于携带。

  4. 用你所想bs,少读书;然后阅读剩余部分bs=1

     dd if=/dev/sdb of=new_image.img bs=4M count=3798
     offset=$((3798*4*1024*1024))
     remaining=$((15931539456-offset))
     dd if=/dev/sdb of=new_image.img bs=1 skip="$offset" seek="$offset" count="$remaining"
    

注意一般情况下dd可能会读取部分块,这仍然会增加计数(比较这个答案)。当从块设备读取时,这可能不会发生,但通用的解决方案仍然是iflag=fullblock每当您依赖countbs大于时始终指定1。不幸的fullblock是 POSIX 并不要求,您dd可能支持也可能不支持。

相关内容