我最近意识到我们可以使用尽可能cat
多的dd
实际上比dd
我知道这dd
对于处理磁带很有用,其中块大小实际上关系到正确性,而不仅仅是性能。然而如今,有没有什么情况是dd
可以做cat
而不能做的呢? (在这里,我认为小于 20% 的性能差异是无关紧要的。)
具体的例子就更好了!
答案1
在外观上,dd
是 IBM 操作系统中的一个工具,保留了其外在外观(其参数传递),它执行一些很少使用的功能(例如 EBCDIC 到 ASCII 的转换或字节顺序反转……现在不常见)。
我曾经认为在同一磁盘上复制大数据块的速度dd
更快(由于更有效地使用缓冲),但这不是真的,至少在今天的 Linux 系统上是这样。
我认为某些dd
选项在处理磁带时很有用,其中读取实际上是按块执行的(磁带驱动程序不会像磁盘驱动程序那样隐藏存储介质上的块)。但我不知道具体情况。
dd
任何其他 POSIX 工具无法(轻松)完成的一件事是取前 N 个字节一条流的。许多系统都可以使用 来完成此操作head -c 42
,但是head -c
虽然很常见,但在 POSIX 中并不存在(并且目前在 OpenBSD 等平台上不可用)。 (tail -c
是 POSIX。)此外,即使head -c
存在,它也可能从源中读取太多字节(因为它内部使用 stdio 缓冲),如果您正在从仅读取就会产生影响的特殊文件中读取,这就是一个问题,或者当其余数据应留给另一个进程读取时,从管道中读取。 (当前的 GNU coreutils 使用 读取精确计数head -c
,但 FreeBSD 和 NetBSD 使用 stdio。)
更一般地说,dd
为底层文件 API 提供一个接口,该接口在 Unix 工具中是唯一的:dd
只能覆盖或截断一份文件在任何一点或者寻找在一个文件中。 (这是dd
独特的能力,而且是一项重要的能力;奇怪的是,它dd
最出名的是其他工具可以做的事情。)
大多数 Unix 工具会覆盖其输出文件,即擦除其内容并从头开始。当您
>
在 shell 中使用重定向时也会发生这种情况。您可以通过
>>
shell 中的重定向或使用tee -a
.如果您想通过删除所有数据来缩短文件在某一点之后,这是由底层内核和 C API 通过
truncate
函数,但不被任何 POSIX 命令行工具公开除了dd
:dd if=/dev/null of=/file/to/truncate seek=1 bs=123456 # truncate file to 123456 bytes
(但是,许多现代系统都提供了
truncate
实用程序。)如果您想覆盖文件中间的数据,同样可以在底层 API 中通过以下方式实现:开幕用于写入而不截断的文件(并调用
lseek
如有必要,移动到所需位置),但只能dd
打开文件而不进行截断或追加,或者寻找从外壳(更复杂的例子)。# zero out the second kB block in the file (i.e. bytes 1024 to 2047) dd if=/dev/zero of=/path/to/file bs=1024 seek=1 count=1 conv=notrunc
所以…作为一个系统工具,dd
几乎没什么用,甚至危险。作为一个文本(或二进制文件)处理工具,它是相当有价值的!
答案2
还没有人提到你可以使用 dd 来创建稀疏文件,但truncate
也可用于相同目的。
dd if=/dev/zero of=sparse-file bs=1 count=1 seek=10GB
这几乎是即时的,并创建一个可以用作环回文件的任意大文件,例如:
loop=`losetup --show -f sparse-file`
mkfs.ext4 $loop
mkdir myloop
mount $loop myloop
好处是它最初只使用单个磁盘空间块,此后仅根据需要增长(10GB 文件的 ext4 格式在我的系统上消耗 291 MB)。用于du
查看实际使用了多少磁盘空间——ls
仅报告文件可能增长到的最大大小。
答案3
该dd
命令包含很多 cat 无法容纳的选项。也许在您的使用案例中, cat 是一个可行的替代品,但它不是 dd 替代品。
一个例子是用来dd
复制某事物的一部分,但不是整个事物。也许您想根据设备上的已知位置从 iso 映像或硬盘驱动器的分区表中间删除一些位。您dd
可以指定允许这些操作的开始、停止和数量选项。
这些选项dd
使其对于细粒度数据操作不可或缺,而cat
* 只能对整个文件对象、设备或流进行操作。
*正如 Gilles 在评论中指出的那样,可以cat
与其他工具结合来隔离某些对象的某些部分,但cat
仍然可以对整个对象进行操作。
答案4
dd
对于备份硬盘驱动器或其他存储设备的引导扇区 ( dd if=/dev/sda of=boot_sector.bin bs=512 count=1
) 以及稍后重写它 ( dd if=boot_sector.bin of=/dev/sda
) 非常有用。它对于备份加密卷的标头同样有用。
cat
也许可以扭曲这样做,但我不相信它的重写部分。很难cat
只读/写一定数量的字节。