我创建了一个 1TB 文件,其中包含随机数据dd if=/dev/urandom of=file bs=1M count=1000000
。现在我检查kill -SIGUSR1 <PID>
进度并得到以下信息:
691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s
我无法解释该警告。它说什么?警告后我的文件真的是随机的还是有问题?800950+1 Datensätze ein
and中的 +0 或 +1 是什么800950+0 Datensätze aus
意思?警告后为+1。是错误计数吗?
答案1
摘要:dd
是一个难以正确使用的古怪工具。尽管有大量教程告诉您这一点,但不要使用它。dd
有一种“unix street cred”的氛围——但如果你真正理解你在做什么,你就会知道你不应该用 10 英尺长的杆子去碰它。
dd
每个块对系统调用进行一次调用read
(由 的值定义bs
)。不保证read
系统调用返回与指定缓冲区大小一样多的数据。这通常适用于常规文件和块设备,但不适用于管道和某些字符设备。看dd什么时候适合复制数据? (或者,什么时候 read() 和 write() 是部分的)了解更多信息。如果read
系统调用返回的数据少于一个完整块,则dd
传输部分块。它仍然复制指定数量的块,因此传输的字节总数小于请求的字节数。
关于“部分读取”的警告正是告诉您这一点:其中一次读取是部分读取,因此dd
传输了不完整的块。在块计数中,+1
表示一个块被部分读取;由于输出计数为+0
,因此所有块都以读取形式写出。
这不会影响数据的随机性:dd
写出的所有字节都是从中读取的字节/dev/urandom
。但您获得的字节数比预期少。
Linux/dev/urandom
可以满足任意大的请求(来源:extract_entropy_user
中drivers/char/random.c
),因此dd
读取它时通常是安全的。然而,读取大量数据需要时间。如果进程收到信号,read
系统调用将在填充其输出缓冲区之前返回。这是正常行为,应用程序应该read
循环调用;dd
由于历史原因,它并没有这样做(dd
它的起源是模糊的,但它似乎最初是作为一种访问磁带的工具,磁带有特殊的要求,并且从未被改编为通用工具)。当您检查进度时,这会向dd
进程发送一个中断读取的信号。您可以选择知道dd
总共要复制多少字节(确保不要中断它 - 没有进度检查,没有暂停),或者知道dd
到目前为止已经复制了多少字节,在这种情况下您无法知道还有多少字节它将复制的字节。
的版本dd
在 GNU coreutils 中(如在非嵌入式 Linux 和 Cygwin 上找到的)有一个标志fullblock
,告诉在循环中dd
调用(和 for 一样),因此总是传输完整的块。错误消息建议您使用它;你应该总是使用它(在输入和输出标志中),除非在非常特殊的情况下(主要是在访问磁带时)——如果你使用它,那就是:通常有更好的解决方案(见下文)。read
write
dd
dd if=/dev/urandom iflag=fullblock of=file bs=1M count=1000000
另一种确定dd
将要执行的操作的可能方法是传递块大小为 1 的块。然后您可以知道从块计数中复制了多少字节,尽管我不确定如果 aread
在读取第一个块之前被中断会发生什么字节(这在实践中不太可能,但有可能发生)。然而,即使有效,速度也非常慢。
一般使用建议dd
是不使用dd
。虽然dd
经常被宣传为访问设备的低级命令,但实际上并非如此:所有的魔法都发生在设备文件(/dev/…
)部分,dd
只是一个普通工具,很可能被误用,从而导致数据丢失。在大多数情况下,有一种更简单、更安全的方法来完成您想要的操作,至少在 Linux 上是这样。
例如,要在文件开头读取一定数量的字节,只需调用head
:
head -c 1000000m </dev/urandom >file
我在我的机器上做了一个快速基准测试,没有观察到dd
大块大小和head
.
如果您需要在开始时跳过一些字节,请通过管道tail
输入head
:
dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output
如果您想查看进度,请调用lsof
查看文件偏移量。这只适用于常规文件(示例中的输出文件),不适用于字符设备。
lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1
您可以致电pv
获得进度报告(比 的更好dd
),但代价是管道中的附加项目(性能方面,几乎察觉不到)。
答案2
dd
当在单次读取中无法获取足够的数据来填充块时,会出现警告。这种情况发生在不稳定或缓慢的数据源中,或者以比您请求的块大小更小的单位写入数据的源中。
数据完整性没有问题,但问题是dd
部分读仍然算作读块。
如果您不使用该count
选项,则警告几乎不重要,这只是性能考虑。但使用 时count
,您将无法获得您请求的数据量。由于部分读取,of
会比count*bs
最后小。
因此,当您使用 时,从技术上讲您也count
应该始终使用。iflag=fullblock
应该+x
是部分块的数量。
答案3
< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file
^这样就可以了。这里的错误信息显然是错误的。dd
的缓冲区是明确的因此,缓冲输入数数您需要显式缓冲的事件。就这些。别买狗屎。