dd 生成一个 32 MB 的随机文件,而不是 1 GB

dd 生成一个 32 MB 的随机文件,而不是 1 GB

我想要生成一个 1 GB 的随机文件,因此我使用了以下命令。

dd if=/dev/urandom of=output bs=1G count=1

但是每次我启动这个命令时我都会得到一个 32 MB 的文件:

<11:58:40>$ dd if=/dev/urandom of=output bs=1G count=1
0+1 records in
0+1 records out
33554431 bytes (34 MB, 32 MiB) copied, 0,288321 s, 116 MB/s

怎么了?

编辑:

感谢这个主题中的精彩答案,我找到了解决方案,该解决方案读取 32 个 32 MB 大小的块,即 1GB:

dd if=/dev/urandom of=output bs=32M count=32

另一种解决方案是直接读取 1 GB 内存,然后写入磁盘。此解决方案占用大量内存,因此不推荐:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock

答案1

bs,缓冲区大小,表示单个读()dd 已完成调用。

(例如,bs=1M count=1和都bs=1k count=1k将生成 1 MiB 的文件,但第一个版本将在一个步骤中完成,而第二个版本将以 1024 个小块的形式完成。)

几乎任何大小的缓冲区都可以读取常规文件(只要该缓冲区适合 RAM),但设备和“虚拟”文件的工作方式通常非常接近单个调用,并且对每次 read() 调用将产生的数据量有一些任意限制。

对于/dev/urandom,此极限定义为urandom_read()驱动程序/char/random.c

#define ENTROPY_SHIFT 3

static ssize_t
urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
    nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
    ...
}

这意味着每次调用该函数时,它都会将请求的大小限制为 33554431 字节。

默认情况下,与大多数其他工具不同,收到的数据少于请求的数据后不会重试 - 您获得 32 MiB,仅此而已。(要使其自动重试,如 Kamil 的回答中所述,您需要指定iflag=fullblock。)


还要注意的是,“单个 read() 的大小”意味着整个缓冲区必须一次装入内存,因此大量的块大小也对应于

这一切都是毫无意义的,因为当超过~16-32 MiB 块时通常不会获得任何性能——系统调用不是这里缓慢的部分,随机数生成器才是。

因此为了简单起见,只需使用head -c 1G /dev/urandom > output

答案2

dd读取的数可能小于ibs(注意:bs同时指定ibsobs),除非iflag=fullblock指定。0+1 records in表示读取了0完整块和1部分块。但是,任何完整块或部分块都会增加计数器。

我不知道在这种特殊情况下dd读取小于的块的具体机制1G。我猜想任何块在写入之前都会被读取到内存中,因此内存管理可能会干扰(但这只是猜测)。编辑:这个并发的答案解释在这种特殊情况下dd读取小于的块的机制。1G

无论如何,我不推荐这么大的bs。我会使用bs=1M count=1024。最重要的是:没有iflag=fullblock 任何读取尝试可能读取少于ibs(除非ibs=1,我认为,这是相当低效的)。

因此,如果您需要读取一定数量的数据,请使用iflag=fullblock。注意iflagPOSIX 不要求这样做,您的dd系统可能支持也可能不支持。根据这个答案 ibs=1可能是读取准确字节数的唯一 POSIX 方法。当然,如果您更改,ibs则需要重新计算count。在您的情况下,降低ibs32M或更低可能会解决问题,即使没有iflag=fullblock

在我的 Kubuntu 中,我会像这样修复你的命令:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock

相关内容