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


16

我使用创建一个包含随机数据的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

我无法解释警告。它说什么?警告后我的文件真的是随机的还是有问题?+0或+1 in 800950+1 Datensätze ein800950+0 Datensätze aus是什么意思?警告后为+1。它是一个错误计数吗?


如果您可以将消息翻译成英文,这将更容易回答。另外,定义“真正随机”。您需要什么级别的随机性,它将用于什么用途?
terdon

要获取英文消息,请LC_ALL=C在命令前面使用,例如LC_ALL=C dd if=...
Volker Siegel

Answers:


38

简介:dd是一个怪异的工具,很难正确使用。尽管有许多教程告诉您,但不要使用它。dd它具有“ unix street cred”的氛围-但如果您真正了解自己在做什么,就会知道不应该用10英尺长的杆子碰它。

ddread每个块(由的值定义bs)对系统调用进行一次调用。不能保证read系统调用返回的数据与指定的缓冲区大小一样多。这通常适用于常规文件和块设备,但不适用于管道和某些字符设备。请参阅dd什么时候适合复制数据?(或何时分别使用read()和write()部分)以获取更多信息。如果read系统调用返回少于一个完整的块,则dd传输一个部分块。它仍然会复制指定数量的块,因此传输的字节总数少于请求的数量。

关于“部分读取”的警告告诉您确切的信息:其中一个读取是部分读取的,因此dd传输了不完整的块。在块计数中,+1表示部分读取了一个块。由于输出计数为+0,因此所有块均被读取读取。

这不会影响数据的随机性:所有dd写出的字节都是从中读取的字节/dev/urandom。但是您得到的字节少于预期。

Linux可以/dev/urandom容纳任意大的请求(来源:extract_entropy_userin drivers/char/random.c),因此dd从它读取时通常是安全的。但是,读取大量数据需要时间。如果该进程收到信号,则read系统调用将在填充其输出缓冲区之前返回。这是正常现象,应用程序应该read循环调用。dd出于历史原因,它不这样做(dd的起源很模糊,但是它似乎最初是作为一种访问磁带的工具,这种磁带具有特殊的要求,并且从未适合用作通用工具)。当您检查进度时,这会向dd进程发送一个信号,该信号会中断读取。您可以选择知道多少个字节dd总共遗嘱副本(确保不中断它-不进行进度检查,不暂停),或知道多少字节dd 到目前为止已复制,在这种情况下,您不知道它将复制多少字节。

ddGNU coreutils中的版本(在非嵌入式Linux和Cygwin上可以找到)带有一个标志fullblock,该标志指示dd调用read循环(和相同write),因此始终传输完整的块。错误消息表明您正在使用它。您应该始终使用它(在输入和输出标志中),除非在非常特殊的情况下(通常在访问磁带时)—如果您完全使用它dd,那就是:通常有更好的解决方案(请参见下文)。

dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000

确定执行该dd操作的另一种可能方法是传递一个块大小为1。然后,您可以知道从块计数中复制了多少字节,尽管我不确定read在读取第一个前a 被中断会发生什么。字节(实际上不太可能,但是可能发生)。但是,即使有效,这也非常慢。

关于使用的一般建议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获取进度报告(优于dds),但要牺牲管道中的其他项目(就性能而言,这几乎是不可感知的)。


2
+1。这是我长期在StackExchange网络上阅读最多的文章之一。它简明扼要,但却包含了dd我不知道我需要知道的有关命令的所有详细信息(历史和当今)。谢谢。
Cosmic Ossifrage 2015年

4
抱歉,您不同意dd是“难以正确使用的怪异工具”和“请勿使用dd”的说法,对此我感到抱歉。如果花了一些时间来理解它的人正确使用了它,则它是一个非常好的工具。实际上,磁盘取证工具包几乎都依赖于dd或诸如dcfldd的派生词。
fpmurphy '16

1
@ fpmurphy1 dd由于可以选择使用GNU,因此可以安全地使用它fullblock。但是,如果您有GNU coreutils,则不需要dd太多。“衍生物”,如dcfldd dd,他们不从它的设计弊病,所以我的答案并不适用于他们。绝大多数使用它的dd人没有花足够的时间来理解它(最多,他们花了时间认为自己理解了它),并且使用它的方式确实导致数据丢失。
吉尔斯

1
@Gilles因此,我们不应该使用可能会被滥用的“ echo” b / c(sudo echo hello world> / dev / sda)?
whitey04年

2
@ whitey04我建议不要处理硝酸甘油桶。我并不是说你不应该使用火柴。
吉尔斯(Gilles)'所以

9

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的缓冲区是显式的,因此,要缓冲输入以计数出现次数,您需要显式缓冲。就这些。不要买这些东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.