从给定的文件中,我需要创建一个用零填充到特定大小的副本。
如果您使用以下内容创建文件。
echo test >testfile
以下命令的输出不一致。
cat testfile /dev/zero | dd bs=256k count=1 status=none | od -c
这是我期望的输出。
0000000 t e s t \n \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
*
1000000
但你也随机得到以下任何一种。
0000000 t e s t \n
0000005
0000000 t e s t \n \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
*
0400000 \0 \0 \0 \0 \0
0400005
为什么这个命令有不一致的行为?
即使 dd 在第一个文件的末尾切断管道,128k 的结果也很奇怪。我在 16.04、18.04 和 19.04 系统下得到相同的不一致结果。
您需要指定完整的块。尝试:
文档
来自
man dd
:例子
观察到,如果没有
fullblock
,字节数是不一致的:使用
iflag=fullbock
,我看到一致的完整字节数:问题的核心是两方面的。问题的一部分是短的或部分的
read()
。根据POSIX 规范:这是典型的管道,这正是问题中发生的事情。一种解决方案是使用 GNU extension
iflag=fullblock
,这是 Ubuntu 使用的版本。来自GNU dd 手册:POSIX
dd
,MirOSdd
,FreeBSDdd
- 这些没有这样的选项(尽管有人要求将其添加到 POSIX 规范中)。那么我们如何编写可移植的脚本dd
,你可能想从 Ubuntu 移植到 FreeBSD 呢?好吧,问题的一部分是count=1
标志。它告诉执行dd
多少次read()
调用。尝试执行多个跟踪dd if=/dev/urandom | strace -e read dd of=/dev/null bs=256k count=1
,你会发现总是只有一个read()
,这通常是部分的。(另请注意,如果您看到读取的是 262144 字节而不是 256,000 字节,请不要感到惊讶,因为 256k 是 256*1024=262144)解决方法是翻转参数,即使块大小
bs=1
和count=256k
. 这样我们就可以确保没有部分读取,并且我们总是读取 1 个字节,但我们会这样做 256k 次。是的,这要慢得多,并且对于千兆字节/兆字节范围内的数据需要更长的时间。在我的测试中,iflag=fullblock
它快了大约 100 倍(256k 字节上的差异在 5 毫秒和 700 毫秒之间)。但是,优点是它是可移植的,并且不必依赖 GNUdd
扩展,尤其是您不能总是安装 GNUdd