bash - 根本不理解 dd 命令参数

标签 bash dd

我对 dd 命令非常熟悉,但我自己很少需要使用它。今天我需要这样做,但我遇到了看起来很奇怪的行为。

我想创建一个 100M 的文本文件,其中每一行都包含一个单词“testing”。这是我的第一次尝试:

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=1M count=100
0+100 records in
0+100 records out
561152 bytes (561 kB) copied, 0.00416429 s, 135 MB/s

嗯,这很奇怪。其他组合呢?

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=100K count=1K
0+1024 records in
0+1024 records out
4268032 bytes (4.3 MB) copied, 0.0353145 s, 121 MB/s

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=10K count=10K
86+10154 records in
86+10154 records out
42524672 bytes (43 MB) copied, 0.35403 s, 120 MB/s

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=1K count=100K
102400+0 records in
102400+0 records out
104857600 bytes (105 MB) copied, 0.879549 s, 119 MB/s

因此,在这四个看似等效的命令中,所有命令都会生成不同大小的文件,其中只有一个符合我的预期。这是为什么?

编辑:顺便说一句,我有点尴尬,我没有想到“是测试”而不是那个更长的 Perl 命令。

最佳答案

要了解发生了什么,让我们看一下类似调用的 strace 的输出:

execve("/bin/dd", ["dd", "of=X", "bs=1M", "count=2"], [/* 72 vars */]) = 0
…
read(0, "testing\ntesting\ntesting\ntesting\n"..., 1048576) = 69632
write(1, "testing\ntesting\ntesting\ntesting\n"..., 69632) = 69632
read(0, "testing\ntesting\ntesting\ntesting\n"..., 1048576) = 8192
write(1, "testing\ntesting\ntesting\ntesting\n"..., 8192) = 8192
close(0)                                = 0
close(1)                                = 0
write(2, "0+2 records in\n0+2 records out\n", 31) = 31
write(2, "77824 bytes (78 kB) copied", 26) = 26
write(2, ", 0.000505796 s, 154 MB/s\n", 26) = 26
…

发生的事情是 dd 进行了一次单个 read() 调用 来读取每个 block 。这在从磁带读取时是合适的,这正是 dd 最初主要用于的目的。在磁带上,read 实际上是读取一个 block 。从文件中读取时,必须注意不要指定太大的 block 大小,否则 read 将被截断。从管道读取时,情况更糟:您读取的 block 的大小将取决于生成数据的命令的速度。

这个故事的寓意是不要使用 dd 来复制数据,除非使用安全的小块。除非使用 bs=1,否则绝不会来自管道。

(GNU dd 有一个 fullblock 标志来告诉它表现得体。但其他实现没有。)

关于bash - 根本不理解 dd 命令参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6782806/

相关文章:

python - 为什么 bash 还在搜索 conda?

c - C程序的管道输出到文件(bash)

linux - 在 bash/sh 中分别通过管道传输 stderr 和 stdout

html - 如何使描述列表中的不同定义彼此相邻 float ?

c# - linux dd命令的Windows C#实现

shell - 使用 shell 将字节插入文件

linux - dd block 大小优化?

bash - 如何在 Unix shell 脚本中查找 `YYYY-MM-DD` 格式的日期与今天日期之间的日差?

bash - 相对于包含模式的行,删除前 n1 行和后 n2 行

bash shell 脚本提示输入数据库密码