我有一个单个磁盘映像的 tar 存档。该 tar 文件内的图像大小约为 4GB。我通过管道将tar xf
into的dd
输出写入到 SD 卡中。直到卡已满,磁盘转储才会停止。这是我的 shell 会话:
$ ls -l disk.img.tgz
-rw-r--r-- 1 confus confus 192M Okt 5 00:53
$ tar -tvf disk.img.tgz
-rw-r--r-- root/root 4294968320 2018-10-05 00:52 disk.img
$ lsblk -lb /dev/sdc
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdc 8:32 1 16022241280 0 disk
$ tar zxf disk.img.tgz -O | sudo dd status=progress conv=sync bs=1M of=/dev/sdc
[sudo] password for user:
15992881152 bytes (16 GB, 15 GiB) copied, 212 s, 75,4 MB/s
dd: error writing '/dev/sdc': No space left on device
0+15281 records in
15280+0 records out
16022241280 bytes (16 GB, 15 GiB) copied, 217,67 s, 73,6 MB/s
为什么?在 hit 将 4GB 映像写入 16GB 购物车后,它应该停止,并且永远不会用完空间!
答案1
那是因为你做错了。
您正在使用bs=1M
但从标准输入、管道读取的读数将会较小。事实上,根据 dd 的说法,你没有得到一个完整的阅读。
然后你就可以用conv=sync
零来补充不完整的读取。
0+15281 records in
15280+0 records out
dd
收到 0 个完整读取和 15281 个不完整读取,并写入 15280 个完整块(conv=同步零填充)。因此输出比输入大得多,直到没有剩余空间为止。
sync pad every input block with NULs to ibs-size; when used with
block or unblock, pad with spaces rather than NULs
要解决此问题,您可以删除conv=sync
并添加iflag=fullblock
.
为了说明这一点,请考虑yes
,默认情况下会输出无限的“y\ny\ny\n”。
$ yes
y
y
y
^C
$ yes | hexdump -C
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a |y.y.y.y.y.y.y.y.|
*
它dd bs=1M conv=sync
看起来像这样:
$ yes | dd bs=1M conv=sync | hexdump -C
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a |y.y.y.y.y.y.y.y.|
*
0001e000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00100000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a |y.y.y.y.y.y.y.y.|
*
00112000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
因此它得到一个不完整的“y\ny\ny\n”块(0x00000 - 0x1e000,122880 字节),然后将剩余的 1M 写入零(0x01e000 - 0x100000,925696 字节)。在大多数情况下,您不希望这种情况发生。无论如何,结果是随机的,因为您无法真正控制每次读取的不完整程度。像这里第二次读取的不再是 122880 字节而是 73728 字节。
dd conv=sync
很少有用,即使在受欢迎的情况下也是如此,比如当你遇到读取错误时写零,事情会变得非常糟糕。