老而不死的dd命令

Last Updated: 2023-06-18 06:25:00 Sunday

-- TOC --

古老的dd命令,在Linux环境下,主要用来做硬盘或分区的镜像导入导出,数据备份,创建虚拟文件系统等等。

其实Linux下的很多命令,都可以说是老而不死的...

用dd命令操作各种设备文件,不需要mount这些设备。据说对mount后的设备操作相对慢很多,建议操作前执行umount。这同时也说明,dd是一个底层的,比较危险的命令,输入命令之前,好好检查各项参数。

基本dd命令操作

创建硬盘镜像

$ sudo dd if=/dev/sda of=~/sda.img

if定义源,of定义目标。必须用=来连接参数值,这似乎是dd命令的一个特色。

我们也可以只对硬盘的某个分区进行镜像创建:

$ sudo dd if=/dev/sda1 of=~/sda1.img bs=4096

bs,block size,设置每次操作的块大小,bs值会影响dd命令的执行速度。

直接创建用gzip压缩的硬盘镜像

$ sudo dd if=/dev/sdb bs=8192 | gzip -1 - | dd of=~/sdb.img.gz status=progress

status=progress,可以让dd命令在工作的时候,显示一点进度信息。

将if指定的源读出后,先经过gzip命令压缩,然后再给of指定的目标。

将远程主机上的分区备份到本地

$ ssh username@host [-p <port>] 'sudo dd if=/dev/vda1 | gzip -1 -' | dd of=~/tt.img.gz status=progress

这里用到了ssh执行远程命令的技巧,让远程主机上的gzip向stdout输出,此时会通过ssh建立的加密网络通道传会本地,然后在本地通过管道接收,dd命令也可以接收stdin的输入。

一般用户使用dd命令访问设备,需要sudo权限,上面这个示例存在一个bug,在远程主机上执行sudo命令,如何输入密码?或者登录执行命令的用户免密,或者使用autopass。

恢复硬盘镜像

$ dd if=~/sda.img of=/dev/sda

就是将if和of反过来。

如果镜像文件是经过压缩的,命令行如下:

$ gzip -dc path/to/img.gz | sudo dd of=/dev/sda status=progress

将ISO写入U盘

将一个iso文件直接写入U盘,用U盘启动设备,就是用iso文件启动:

$ sudo dd if=path/to/file.iso of=/dev/sdc bs=4096 status=progress

创建大文件

$ dd if=/dev/zero of=~/abigfile.img bs=1M count=1024

count表示次数,即每次读1M的zero,写入abigfile.img,一共执行1024次,因此最后abigfile.img文件的大小就是1G。

彻底清除硬盘内容

不管是分区,还是格式化,都不能彻底清除硬盘扇区中的数据,但dd可以:

$ sudo if=/dev/zero of=/dev/sda bs=4096 status=progress
$ sudo if=/dev/urandom of=/dev/sda bs=4096 status=progress

是不是写入随机数更好,看你的场景了。

以上两个命令,都会将硬盘上的所有数据全部抹去,写入会执行到of指定的设备没有空间为止。测试发现用if=/dev/zero会稍微快一点点。

用这种方式清除硬盘上的数据,是非常彻底的,任何工具都无法恢复,因此自己在使用时,要非常小心。

这种清除数据的方式,与低级格式化不同。

低级格式化是将空白的磁盘划分出柱面和磁道,再将磁道划分为若干个扇区,每个扇区又划分出标识ID、间隔区GAP和数据区DATA等,它是高级格式化之前的一个流程。而dd命令只是通过写入全0或随机数的方式,将数据全部删除。

估测硬盘IO速度

dd命令可以用来估测硬盘IO速度。注意,只是估计测试哈!

估测硬盘写入速度

$ dd if=/dev/zero of=./10GiB.file bs=1K count=10000000 status=progress
10218874880 bytes (10 GB, 9.5 GiB) copied, 94 s, 109 MB/s
10000000+0 records in
10000000+0 records out
10240000000 bytes (10 GB, 9.5 GiB) copied, 94.2684 s, 109 MB/s

读取/dev/zero不会产生IO,因此只有写入文件的IO操作!

我们还可以通过设置不同的写入块大小,测试出大致的最佳写入速度:

$ dd if=/dev/zero of=./10GiB.file bs=2K count=5000000 status=progress
$ dd if=/dev/zero of=./10GiB.file bs=4K count=2500000 status=progress
$ dd if=/dev/zero of=./10GiB.file bs=10K count=1000000 status=progress

我个人在虚拟机上的测试,似乎看不出明显区别!

估测硬盘读取速度

$ sudo dd if=/dev/sda of=/dev/null bs=1K count=10000000 status=progress
10128360448 bytes (10 GB, 9.4 GiB) copied, 76 s, 133 MB/s
10000000+0 records in
10000000+0 records out
10240000000 bytes (10 GB, 9.5 GiB) copied, 76.7825 s, 133 MB/s

写入/dev/null不会产生IO,因此只有读取IO!

估测同时读写速度

在dd命令行不使用伪设备,if和of都是硬盘,此时就是同时读写。

$ sudo dd if=/dev/sda of=./10GiB.test bs=1K count=10000000 status=progress
10202371072 bytes (10 GB, 9.5 GiB) copied, 163 s, 62.6 MB/s
10000000+0 records in
10000000+0 records out
10240000000 bytes (10 GB, 9.5 GiB) copied, 163.969 s, 62.5 MB/s

注意:dd命令只能提供一个大概的测试结果,而且是连续I/O,不是随机I/O,理论上文件规模越大,测试结果越准确。 同时,iflag/oflag提供direct模式,direct模式是把写入请求直接封装成I/O指令发到硬盘,非direct模式只是把数据写入到系统缓存就认为I/O成功,并由操作系统决定缓存中的数据什么时候被写入磁盘。

具体如何使用iflag/oflag,以及各种选项的含义,请参考dd命令的manual page。

直接读写扇区

Linux下有好些个工具都可以直接读取设备文件,xxd或hexdump命令,当然dd命令也可以,使用dd命令,可以方便的将读取的扇区数据保存到文件。而写入扇区,只有dd命令。

$ sudo dd if=/dev/sdb of=./lba0 bs=512 count=1
$ ...
$ sudo dd of=./lba0 if=/dev/sdb bs=512 count=1

精准控制读写位置,需要设置更多参数:

seek=N skip N obs-sized blocks at start of output
skip=N skip N ibs-sized blocks at start of input

本文链接:https://cs.pynote.net/sf/linux/shell/202201042/

-- EOF --

-- MORE --