我在ubuntu系统上运行以下命令:
dd if=/dev/random of=rand bs=1K count=2
但是,每次运行它时,最终都会得到一个不同大小的文件。为什么是这样?如何生成具有随机数据的给定大小的文件?
iflag=fullblock
我在ubuntu系统上运行以下命令:
dd if=/dev/random of=rand bs=1K count=2
但是,每次运行它时,最终都会得到一个不同大小的文件。为什么是这样?如何生成具有随机数据的给定大小的文件?
iflag=fullblock
Answers:
您正在观察dd
的独特行为与Linux的独特行为的结合/dev/random
。顺便说一下,两者都不是完成这项工作的正确工具。
Linux /dev/random
很少返回数据。它基于这样的假设:伪随机数生成器中的熵以非常快的速率被熄灭。由于收集新的熵很慢,因此/dev/random
通常一次只放弃几个字节。
dd
是一个古老的,古怪的程序,最初旨在在磁带设备上运行。当您告诉它读取1kB的一个块时,它将尝试读取一个块。如果读取返回的数据少于1024个字节,那么,仅此而已。因此dd if=/dev/random bs=1K count=2
打了两个read(2)
电话。由于是从读取/dev/random
,因此两个read
调用通常仅返回几个字节,其数量取决于可用的熵。另请参阅dd什么时候适合复制数据?(或者,何时分别使用read()和write())
除非您正在设计OS安装程序或克隆程序,否则永远不要/dev/random
在Linux下使用/dev/urandom
。该urandom
手册页有所误导; /dev/urandom
实际上,它适用于加密,甚至可以生成长期存在的密钥。唯一的限制/dev/urandom
是必须提供足够的熵。Linux发行版通常在重新启动之间保存熵,因此,唯一可能没有足够熵的情况是全新安装。实际上,熵不会消失。有关更多信息,请阅读/ dev / urandom中的兰特对于登录密钥是否安全?和喂/ dev / random熵池?。
dd
诸如head
或的工具可以更好地表达的大多数用法tail
。如果要2kB的随机字节,请运行
head -c 2k </dev/urandom >rand
使用较旧的Linux内核,您可以摆脱困境
dd if=/dev/urandom of=rand bs=1k count=2
因为很/dev/urandom
高兴返回了所请求的字节数。但是,从内核3.16开始,情况已不再如此,现在限制为32MB。
通常,当您需要dd
提取固定数量的字节并且其输入不是来自常规文件或块设备时,则需要逐字节读取:dd bs=1 count=2048
。
dd if=/dev/urandom ibs=1k obs=1k | dd bs=1k count=2
从man 4 random
在RHEL 5盒:
读取时,/ dev / random设备将仅返回熵池中估计的噪声位数内的随机字节。
我在那台机器上得到大小为213字节的文件。回到男人4随机:
读取时,/ dev / urandom设备将返回所请求的字节数。
我每次调用都会得到2048个字节 dd if=/dev/urandom of=rand bs=1K count=2
我的结论是,差异是由于您的计算机在两次调用之间产生了多少熵 dd if=/dev/random ...
dd if=/dev/random bs=1K count=2
在熵池明显耗尽时为什么会停止感到困惑。从文档开始,它应该阻塞直到出现更多的熵为止,因此dd
它将缓慢地写出文件,而不是仅转储当前池并退出。
read(fd, mybuf, 1024)
阻塞的FD时,它会在基础设备返回一些数据后立即返回。如果要读取1024个字节,它将返回该字节。如果只有201个字节,它将返回201。如果有0个字节,它将阻塞直到至少一个字节变为可用,然后再返回。
为什么要dd
丢弃数据?... Gilles提出了一个有关dd
以下问题:
dd什么时候适合复制数据?(或者,当部分为read()和write()时)
这是该问题的摘录:
* ...将dd置于错误并不难;例如,尝试以下代码:**
yes | dd of=out bs=1024k count=10
并检查out文件的大小(该文件的大小很可能在10MB以下)。
除了我的评论(在您问题的末尾)之外,类似的事情很令人讨厌……它捕获了file中的字节$trnd
。我半任意选择bs = 8
移动鼠标并观看它的加速。
在我的计算机空闲(AFK并且没有网络活动)的情况下,并且在耗尽了熵池之后,花了2 小时 12分钟才能收集到1192个字节,这时我取消了它。
然后,随着我不断移动鼠标,收集相同数量的字节花了相对较短的1 分 15秒。
这很清楚地表明,收集熵不是基于CPU速度的,而是基于随机事件的,并且我的Ubuntu系统使用鼠标作为其重要的随机因素之一。
get=2048
trnd=/tmp/$USER.rnd; >"$trnd"
while (( $(wc -c <"$trnd") < $get )) ;do
dd if=/dev/random bs=8 count=1 2>/dev/null >>"$trnd"
echo -n "itt: $((i+=1)) ct: "; wc -c <"$trnd"
done
truncate -s $get "$trnd"
echo -e "\nfinal count: "; wc -c <"$trnd"
dd
专为阻塞而设计 -如果您需要立即完成操作,它通常是最好的工具,可用于读取可变大小的输入,因为dd
这不会缓冲将来的电流读取write()
(除非您使用比ibs大的obs来明确配置),而是将write()
一切早点读,因为它read()
的IT (以及可选的处理它)。
以下是一些重要的定义:
ibs=
expr
expr
obs=
expr
expr
bs=
expr
expr
字节,ibs=
并替换为和obs=
。如果没有转换以外sync
,noerror
和notrunc
被指定时,每一个输入块应被复制到输出为单个块,而不聚集短块。因此,您会看到,何时ibs
和obs
一起定义时,bs
则ibs
优先-否则,如果您是特定的,则选择obs
或cbs
做。
这是ibs
最重要的示例。如果要跟踪/dev/random
池填充的时间,可以执行以下操作:
dd "ibs=$size" conv=sync "count=$lmt" \
if=/dev/random of="$somefile"
只要if=
目标完全可读,它就会始终生成相同大小的输出文件,因为dd
它将sync
对null读取的块进行hronize。换句话说,如果dd
read()
s是一个输入$((size=10))
$((count=5))
时间块,并且read()
文件返回2个字节,那么该文件将返回8个字节,然后是12个字节,然后是2个字节,然后是4个字节,dd
将写入其输出文件,例如
2 read bytes 8NULs \
8 read bytes 2NULs \
10 read bytes 0NULs \
4 read bytes 6NULs \
4 read bytes 6NULs
...因为dd
默认情况下不会延迟。因此,如果您需要跟踪插播广告并划定其他流程的写入内容,dd
则此工具非常适合您。
如果您只是向常规文件中写入一些数据,那么与此处所做的其他声明相反,您也可以dd
轻松地用于此目的,但是您将需要多个和一个可靠的阻塞因子。
例如,如果您这样做:
{ dd ibs="$size" obs="${size}x$block_factor" |
dd bs="${size}x$blockfactor" "count=$lmt"
} <infile >outfile
...第一个dd
缓冲区将缓冲尽可能多的ibs="$size"
输入块,以填充至少一个obs="${size}x$block_factor"
输出块,write()
直到每个输入块与第二个之间的管道为止dd
。这意味着,第二dd
可以可靠地限制输出count="$lmt"
,因为所有的write()
S中的第一品牌将匹配其I / O块大小- 无论有多少read()
上了第一dd
必须做的是真的。
这就是您dd
仅需一点点数学就可以用来可靠地读取管道或其他类型的特殊文件的方法。
/dev/random
如果没有足够的熵来生成所需的位数,则将阻止。收集大量高质量的伪随机“随机性”只需要花费时间...要么使用随机性/dev/urandom
较低的“随机性”值,要么检查您的熵池(循环检查,然后根据需要等待)...