使用 dd 创建随机数据并获得“部分读取警告”。现在警告后的数据真的是随机的吗?

使用 dd 创建随机数据并获得“部分读取警告”。现在警告后的数据真的是随机的吗?

我创建了一个 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 einand中的 +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_userdrivers/char/random.c),因此dd读取它时通常是安全的。然而,读取大量数据需要时间。如果进程收到信号,read系统调用将在填充其输出缓冲区之前返回。这是正常行为,应用程序应该read循环调用;dd由于历史原因,它并没有这样做(dd它的起源是模糊的,但它似乎最初是作为一种访问磁带的工具,磁带有特殊的要求,并且从未被改编为通用工具)。当您检查进度时,这会向dd进程发送一个中断读取的信号。您可以选择知道dd总共要复制多少字节(确保不要中断它 - 没有进度检查,没有暂停),或者知道dd到目前为止已经复制了多少字节,在这种情况下您无法知道还有多少字节它将复制的字节。

的版本dd在 GNU coreutils 中(如在非嵌入式 Linux 和 Cygwin 上找到的)有一个标志fullblock,告诉在循环中dd调用(和 for 一样),因此总是传输完整的块。错误消息建议您使用它;你应该总是使用它(在输入和输出标志中),除非在非常特殊的情况下(主要是在访问磁带时)——如果你使用它,那就是:通常有更好的解决方案(见下文)。readwritedd

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的缓冲区是明确的因此,缓冲输入数数您需要显式缓冲的事件。就这些。别买狗屎。

相关内容