我想要生成一个 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
同时指定ibs
和obs
),除非iflag=fullblock
指定。0+1 records in
表示读取了0
完整块和1
部分块。但是,任何完整块或部分块都会增加计数器。
我不知道在这种特殊情况下编辑:这个并发的答案解释在这种特殊情况下dd
读取小于的块的具体机制1G
。我猜想任何块在写入之前都会被读取到内存中,因此内存管理可能会干扰(但这只是猜测)。dd
读取小于的块的机制。1G
无论如何,我不推荐这么大的bs
。我会使用bs=1M count=1024
。最重要的是:没有iflag=fullblock
任何读取尝试可能读取少于ibs
(除非ibs=1
,我认为,这是相当低效的)。
因此,如果您需要读取一定数量的数据,请使用iflag=fullblock
。注意iflag
POSIX 不要求这样做,您的dd
系统可能支持也可能不支持。根据这个答案 ibs=1
可能是读取准确字节数的唯一 POSIX 方法。当然,如果您更改,ibs
则需要重新计算count
。在您的情况下,降低ibs
到32M
或更低可能会解决问题,即使没有iflag=fullblock
。
在我的 Kubuntu 中,我会像这样修复你的命令:
dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock