刚刚遇到这个问题,并从所选答案中学到了很多东西:使用 dd 创建随机数据并获得“部分读取警告”。现在警告后的数据真的是随机的吗?
不幸的是,建议的解决方案head -c
不可移植。
对于坚持认为这dd
是答案的人,请仔细阅读链接的答案,其中详细解释了为什么dd
不能作为答案。另外,请注意这一点:
$ dd bs=1000000 count=10 if=/dev/random of=random
dd: warning: partial read (89 bytes); suggest iflag=fullblock
0+10 records in
0+10 records out
143 bytes (143 B) copied, 99.3918 s, 0.0 kB/s
$ ls -l random ; du -kP random
-rw-rw-r-- 1 me me 143 Apr 22 19:19 random
4 random
$ pwd
/tmp
答案1
不幸的是,操作二进制文件的内容dd
几乎是 POSIX 中唯一的工具。尽管文本处理工具的大多数现代实现(cat
、sed
、awk
、 ...)可以操作二进制文件,但这不是 POSIX 所要求的:一些较旧的实现确实会因空字节、未由换行符终止的输入或环境字符中的无效字节序列而阻塞编码。
安全使用是可能的,但很困难dd
。我花费大量精力引导人们远离它的原因是,有很多建议dd
在它既无用又不安全的情况下进行推广。
问题在于dd
它的块概念:它假设调用read
返回一个区块;如果read
返回较少的数据,您会得到一个部分块,这会抛出诸如skip
和count
off 之类的东西。下面的示例说明了该问题,其中dd
从传输数据相对较慢的管道中读取数据:
yes hello | while read line; do echo $line; done | dd ibs=4 count=1000 | wc -c
在沼泽标准 Linux(Debian jessie,Linux 内核 3.16,dd
来自 GNU coreutils 8.23)上,我得到的字节数变化很大,范围从大约 3000 到几乎 4000。将输入块大小更改为 6 的除数,然后输出始终是 4000 字节,正如人们天真的期望的那样 - 输入dd
以 6 字节的突发形式到达,并且只要一个块不跨越多个突发,dd
就可以读取完整的块。
这提出了一个解决方案:使用输入块大小 1。无论输入是如何产生的,dd
如果输入块大小为 1,则无法读取部分块。(这并不完全明显:dd
如果被信号中断,则可以读取大小为 0 的块 - 但如果它被中断通过信号,read
系统调用返回 -1。read
仅当文件以非阻塞模式打开时,才可能返回 0,在这种情况下,最好不要认为仅read
在阻塞模式下执行过。read
在文件末尾返回 0。)
dd ibs=1 count="$number_of_bytes"
这种方法的问题在于它可能很慢(但不是慢得惊人:只比head -c
我的快速基准测试慢大约 4 倍)。
POSIX 定义了其他读取二进制数据并将其转换为文本格式的工具:uuencode
(以历史 uuencode 格式或 Base64 输出),od
(输出八进制或十六进制转储)。两者都不太适合手头的任务。uuencode
可以通过以下方式撤消uudecode
,但是计算输出中的字节数很尴尬,因为每行输出的字节数没有标准化。可以从 获得明确定义的输出od
,但不幸的是没有 POSIX 工具可以反过来(可以做到,但只能通过 sh 或 awk 中的慢循环,这违背了这里的目的)。
答案2
较新版本的 GNU 实现dd
有一个count_bytes
iflag。例如:
cat /dev/zero | dd count=1234 iflag=count_bytes | wc -c
会输出类似的东西
2+1 records in
2+1 records out
1234 bytes (1.2 kB, 1.2 KiB) copied, 0.000161684 s, 7.6 MB/s
1234
答案3
使用的部分目的dd
是用户可以选择它使用的块大小。如果dd
块大小太大而失败,IMO 用户有责任尝试较小的块大小。我可以要求dd
一个街区的 TB,但这并不意味着我会得到它。
如果您想要确切的字节数,这将非常慢,但应该可以工作:
dd bs=1 count=1000000
如果即使是一个块大小也会1
导致部分读取,……