dd

作者:Sam Chessman

dd 命令是最初的 Unix 实用程序之一,应该在每个人的工具箱中。它可以剥离文件头,提取二进制文件的部分内容,并写入软盘的中间部分;Linux 内核 Makefile 使用它来制作启动镜像。它可以用于复制和转换磁带格式,在 ASCII 和 EBCDIC 之间转换,交换字节,以及强制转换为大写和小写。

对于块 I/O,dd 命令在标准工具集中没有竞争对手。人们可以编写自定义实用程序来执行特定的 I/O 或格式化,但是,由于 dd 几乎在任何地方都可用,因此使用它是合理的。

像大多数行为良好的命令一样,dd 从其标准输入读取,并写入其标准输出,除非已给出命令行规范。这允许 dd 在管道中使用,以及通过 rsh 远程 shell 命令远程使用。

与大多数命令不同,dd 对其参数使用 keyword=value 格式。据说这是仿照 IBM System/360 JCL 建模的,后者对于 I/O 设备具有详尽的 DD “数据集定义”规范。所有关键字的完整列表可从 GNU dd 中获取,使用

dd --help

有些人认为 dd 的意思是 “Destroy Disk”(破坏磁盘)或 “Delete Data”(删除数据),因为如果误用,分区或输出文件可能会被非常迅速地破坏。由于 dd 是用于写入磁盘头、引导记录和类似系统数据区域的工具,因此误用 dd 可能已经破坏了许多硬盘和文件系统。

本质上,dd 复制并可选地转换数据。它使用输入缓冲区、转换缓冲区(如果指定了转换)和输出缓冲区。读取操作针对输入文件或设备发出,读取大小为输入缓冲区的大小,应用可选的转换,然后针对输出缓冲区的大小发出写入操作。这允许 I/O 请求根据任务的需求进行定制。输出到标准错误报告读取和写入的完整和短块的数量。

示例 1

dd 的一个典型任务是复制软盘。由于 3.5 英寸软盘的常见几何结构是每磁道 18 个扇区,两个磁头和 80 个柱面,因此读取软盘的优化 dd 命令是

示例 1a:从 3.5 英寸软盘复制:dd bs=2x80x18b if=/dev/fd0 of=/tmp/floppy.image1+0 records in1+0 records out

18b 指定 18 个扇区,每个扇区 512 字节,2x 将扇区大小乘以磁头数,而 80x 用于柱面—总共 1474560 字节。 这向 /dev/fd0 发出单个 1474560 字节的读取请求,并向 /tmp/floppy.image 发出单个 1474560 字节的写入请求,而相应的 cp 命令

cp /dev/fd0 /tmp/floppy.image

发出 360 次 4096 字节的读取和写入。虽然这在 1.44MB 文件上可能看起来微不足道,但是当涉及更大量的数据时,减少系统调用次数和提高性能可能非常重要。

此示例还显示了 GNU dd 数字规范中的因子功能。 这早在程序员工作台之前就存在了,虽然没有在 GNU dd 手册页中记录,但它存在于源代码中并且工作正常,谢谢。

要完成复制软盘,需要弹出原始软盘,插入新磁盘,并发出另一个 dd 命令以写入磁盘

示例 1b:复制 到 3.5 英寸软盘dd bs=2x80x18b < /tmp/floppy.image > /dev/fd01+0 records in1+0 records out

这里展示了 stdin/stdout 的用法,在这方面,dd 像大多数其他实用程序一样。

示例 2

最初对 dd 的需求来自于 1/2 英寸磁带,这些磁带用于与其他系统交换数据,并在 PDP/11 上启动和安装 Unix。 那些日子已经过去了,但 9 磁道格式仍然存在。 要访问古老的 9 磁道、1/2 英寸磁带,dd 是更优的选择。 使用现代 SCSI 磁带设备,分块和取消分块不再是必需的,因为硬件读取和写入 512 字节的数据块。

然而,9 磁道 1/2 英寸磁带格式允许可变长度分块,并且可能无法使用 cp 命令读取。 dd 命令允许精确指定输入和输出块大小,甚至可以通过指定大于磁带上任何块的输入缓冲区大小来读取可变长度块大小。 读取短块时,dd 会愉快地将其复制到输出文件,而不会报错,只是报告遇到的完整块和短块的数量。

还有从 MVS 等系统传输的 EBCDIC 数据集,这些数据集几乎总是 80 字符的空格填充 Hollerith 卡片图像! 这对 dd 来说不是问题,它会将这些数据转换为换行符终止的可变记录长度 ASCII。 创建格式同样容易,dd 仍然是完成这项工作的正确工具。

示例 2:将 EBCDIC 80 字符固定长度记录转换为 ASCII 可变长度换行符终止记录dd bs=10240 cbs=80 conv=ascii,unblock if=/dev/st0 of=ascii.out40+0 records in38+1 records out

固定记录长度由 cbs=80 参数指定,输入和输出块大小通过 bs=10240 设置。 EBCDIC 到 ASCII 的转换以及固定到可变记录长度的转换通过 conv=ascii,unblock 参数启用。

请注意,输出记录计数小于输入记录计数。 这是由于从输出文件中删除了填充空格并替换为换行符。

示例 3

有时数据来自格式不寻常的源。 例如,每次我读取 SGI 机器上制作的磁带时,字节都会被交换。 dd 命令从容应对这种情况,根据需要交换字节。 在管道中将 dd 与 rsh 一起使用的能力意味着可以访问任何 *nix 系统上的磁带设备,前提是设置了正确的 rlogin。

示例 3:通过远程访问磁带进行字节交换:rsh sgi.with.tape dd bs=256b if=/dev/rmt0 conv=swab | tar xvf -

dd 在 SGI 上运行,并在写入本地主机上运行的 tar 命令之前交换字节。

示例 4

墨菲定律在数字计算机出现之前很久就被提出,但似乎它是专门针对数字计算机的。 当您需要读取软盘或磁带时,它是宇宙中唯一的副本,并且您的截止日期已过,那时您将在磁介质上遇到坏点,并且您的数据将不可读。 dd 及时出现,它可以读取坏点周围的所有好数据,并在遇到错误后继续。 有时,这足以恢复重要数据。

示例 4:错误处理:dd bs=265b conv=noerror if=/dev/st0 of=/tmp/bad.tape.image

示例 5

Linux 内核 Makefile 使用 dd 来构建启动镜像。 在 Alpha Makefile /usr/src/linux/arch/alpha/boot/Makefile 中,srmboot 目标发出命令

示例 5. 内核镜像 Makefile:dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1

这会跳过输入 bootimage 文件的前 512 个字节 (skip=1),并从 $(BOOTDEV) 设备的第二个扇区 (seek=1) 开始写入。 dd 的一个典型用途是跳过可执行文件头,并开始在设备的中间写入,跳过卷和分区数据。 由于这可能会导致您的磁盘丢失文件系统数据,请谨慎测试和使用这些应用程序。

致谢

dd 命令自 1970 年代以来就已存在,已移植到许多系统,重写多次,并经过时间考验,证明它是一个有用的工具。 当前的 Linux 版本是 GNU dd GNU fileutils 3.12,由 Paul Rubin、David MacKenzie 和 Stuart Kemp 编写,版权所有 © 1985、1990、1991 Free Software Foundation, Inc.

GNU dd 可以在 fileutils 集合中找到,当前版本位于 URL ftp://prep.ai.mit.edu/pub/gnu/fileutils-3.12.tar.gz 或您附近的镜像站点。

其他主要版本包括 SYSV 和 BSD,BSD 源代码版本 5.16 4/28/93 源自加利福尼亚大学圣地亚哥分校的 Keith Muller 和 Convex Computer Corporation 的 Lance Visser 贡献给伯克利的软件,版权所有 © 1991 The Regents of the University of California。

Sam Chessman (SSC3) (chessman@wauug.erols.com)

加载 Disqus 评论