详解Linux转换和复制(dd命令)

一:语法说明

dd命令是一个用于在Linux或Unix系统中执行低级别I/O操作的工具。它允许用户以指定块大小从输入源复制数据,并将数据写入输出目标。其主要的作用就是转换和复制文件

(一):参数选项

bash 复制代码
参数说明:
    if=文件名:
        输入文件名,默认为标准输入。即指定源文件。(全称:input file)
    of=文件名:
        输出文件名,默认为标准输出。即指定目的文件。(全称:output file)
    obs=字节数:
        代表一次写入的字节数,默认一次性512字节;
    ibs=字节数:
        代表一次读取的字节数,默认一次性512字节;
    bs=字节数:
        代表一次读取和写入的字节数,默认一次性512字节;(这个就是obs和ibs的结合;会覆盖ibs和obs的值)
        注:obs、ibs、bs可简便写成如1024,1K,1024M,10G等这样带单位的值
    count=N:
        只复制N个输入块,块大小取决于ibs指定的字节数(N * ibs)
    status=显示等级:
        用于显示复制或转换操作的进度信息,需要设置显示等级;
    iflag=标志:
        按照以逗号分隔的符号列表指定的方式读取(比如异步或者同步读取)
    oflag=标志:
        按照以逗号分隔的符号列表指定的方式写入(比如异步或者同步读取)
    conv=转换:
        按照以逗号分隔的符号列表指定的方式转换文件(比如把文件内的大写字符全部转换为小写)
    cbs=字节数:
        一次转换的字节数(可以参考bs的字节数写法)
    seek=块数:
        在输出开始处跳过指定的 obs 大小的块数(比如这个可以备份指定位置数据块,如MBR备份)
    skip=块数:
        在输入开始处跳过指定的 ibs 大小的块数(比如这个可以备份指定位置数据块,如MBR备份)
        
参数中参数的可选值:
    显示等级:
        none:仅输出错误信息,若复制或转换成功则不会显示任何执行信息;
        noxfer:将不输出最终传输统计信息,但记录读入和写成,示例输出:
                记录了245760+0 的读入
                记录了245760+0 的写出
        progress:将显示周期性的传输统计信息,显示最全的一种,示例输出:
                120742400字节(121 MB,115 MiB)已复制,15 s,8.0 MB/s    ## 这个是实时变化
                记录了245760+0 的读入
                记录了245760+0 的写出
                125829120字节(126 MB,120 MiB)已复制,16.6315 s,7.6 MB/s
    标志:
        append:       追加模式(仅对输出有意义;隐含了 conv=notrunc)
        direct:       使用直接 I/O 存取数据
        directory:    除非是目录,否则操作失败
        dsync:        使用同步 I/O 存取数据
        sync:         与上一个类似,但同时也对元数据生效
        fullblock:    累积完整的输入块(仅限 iflag)
        nonblock:     使用无阻塞 I/O
        noatime:      不更新访问时间
        nocache:      请求不使用缓存。也请参见 oflag=sync
        noctty:       不根据文件指派控制终端
        nofollow:     不跟随符号链接
        count_bytes:  把 "count=N" 看作字节计数(仅限 iflag)
        skip_bytes:   把 "skip=N" 看作字节计数(仅限 iflag)
        seek_bytes:   把 "seek=N" 看作字节计数(仅限 oflag)
    conv选项:
        ascii:     由 EBCDIC 码转换至 ASCII 码
        ebcdic:    由 ASCII 码转换至 EBCDIC 码
        ibm:       由 ASCII 码转换至代用的 EBCDIC 码
        block:     在以换行符结尾的记录末尾填充空格,直至 cbs 大小
        unblock:   将 cbs 大小的记录中的末尾空格替换为一个换行符
        lcase:     将大写字符转换为小写
        ucase:     将小写字符转换为大写
        sparse:    尝试寻址 (seek) 而非写入全为 NUL 空字符的输出块
        swab:      交换每一对输入字节
        sync:      将每个输入块以 NUL 空字符填充至 ibs 大小;
                    当配合 block 或 unblock 使用时,会以空格代替 NUL 空字符来填充
        excl:      如果输出文件已存在,则操作失败
        nocreat:   不要创建输出文件
        notrunc:   不要截断输出文件
        noerror:   发生读取错误后仍然继续
        fdatasync: 结束前将输出文件数据从物理上写入磁盘
        fsync:     与上一个类似,但也将元数据一同写入

(二):命令示例

1:将本地的/dev/vdb1的磁盘分区数据备份到/dev/vdb2

bash 复制代码
磁盘分区情况:
    >> lsblk /dev/vdb
            NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
            vdb    252:16   0   10G  0 disk
            ├─vdb1 252:17   0  120M  0 part /mnt/guazai1
            ├─vdb2 252:18   0  120M  0 part
            └─vdb3 252:19   0  512M  0 part
把vdb1的数据备份到vdb2:
    '>>' dd if=/dev/vdb1 of=/dev/vdb2 status=progress
            123523584字节(124 MB,118 MiB)已复制,17 s,7.3 MB/s
            记录了245760+0 的读入
            记录了245760+0 的写出
            125829120字节(126 MB,120 MiB)已复制,17.4608 s,7.2 MB/s
注意点:
    Ⅰ:磁盘分区vdb1的数据备份到磁盘分区vdb2以后,vdb2的原本数据将丢失;
    Ⅱ:在备份前,磁盘分区vdb2不能在挂载的情况下进行备份操作,而vdb1则无要求;
    Ⅲ:备份磁盘时,推荐两个磁盘的容量最好一样,防止备份的数据太大,装不下;  
    Ⅳ:备份磁盘时,一定要保证两个磁盘的文件系统一致,否则会将恢复的磁盘强制更改为备份的磁盘文件系统;
    
其它说明:
    若挂载时报如:"mount: /mnt/guazai1: can't read superblock on /dev/vdb1."
    需要使用fsck修复指定分区,如这里需要执行:fsck /dev/vdb1 -y

2:将本地的/dev/vdb1全盘的数据备份到指定路径的backups文件中后,再进行恢复操作

bash 复制代码
开始备份数据到/opt/backupsFile.back文件中
    '>>' dd if=/dev/vdb1 of=/opt/backupsFile.back status=progress
            记录了245760+0 的读入
            记录了245760+0 的写出
            125829120字节(126 MB,120 MiB)已复制,0.632166 s,199 MB/s
    >> ls -lh /opt      ## 可以看出vdb1磁盘的分区是120M,复制的文件也是120M
            总计 120M
            -rw-r--r-- 1 root root 120M  1月 27 00:33 backupsFile.back
将备份的backupsFile.back文件恢复到指定的磁盘中(恢复到哪个磁盘分区里都行,只不过会覆盖磁盘数据)
    '>>' dd if=/opt/backupsFile.back of=/dev/vdb1 status=progress
            dd if=/opt/backupsFile.back of=/dev/vdb2 status=progress
            120435200字节(120 MB,115 MiB)已复制,17 s,7.1 MB/s
            记录了245760+0 的读入
            记录了245760+0 的写出
            125829120字节(126 MB,120 MiB)已复制,18.0011 s,7.0 MB/s
将恢复盘挂载到目录中(可以去目录查看数据)
    >> mount /dev/vdb2 /mnt/guazai2
"注意事项和其它说明请参考上面1"

3:将/dev/vdb1磁盘分区里的全部数据备份成.gz压缩文件,并利用gzip工具进行解压恢复

bash 复制代码
实现功能:
    我需要将/dev/vdb1磁盘分区内的全部数据备份压缩到/opt/backups.gz文件里;
    并将数据恢复到/dev/vdb2磁盘分区内(恢复到哪个磁盘分区内都行)
备份/dev/vdb1全盘数据,并利用gzip工具进行压缩,保存到/opt/backups.gz指定的文件里:
    '>>' dd if=/dev/vdb1 status=progress | gzip > /opt/backups.gz
            109574656字节(110 MB,104 MiB)已复制,2 s,54.8 MB/s
            记录了245760+0 的读入
            记录了245760+0 的写出
            125829120字节(126 MB,120 MiB)已复制,2.53575 s,49.6 MB/s
    >> ls -lh /opt
            -rw-r--r-- 1 root root 57M  1月 27 13:50 backups.gz
            ## 发现被压缩了,原来120M的磁盘分区,备份压缩就57M
将压缩的备份文件恢复到/dev/vdb2(恢复后会覆盖原先vdb2的数据,且vdb2不能在挂载时操作)
    '>>' gzip -dc /opt/backups.gz | dd of=/dev/vdb2 status=progress
            118137344字节(118 MB,113 MiB)已复制,15 s,7.9 MB/s
            记录了245760+0 的读入
            记录了245760+0 的写出
            125829120字节(126 MB,120 MiB)已复制,16.2836 s,7.7 MB/s
    >> mount /dev/vdb2 /mnt/guazai2
            mount: /mnt/guazai2: can't read superblock on /dev/vdb2.'    (## 出现这种问题)
            解决:fsck /dev/vdb2 -y    ## 然后再次挂载就行了
"注意事项和其它说明请参考上面1"

4:生成指定大小的文件(一般创建swap虚拟内存时用的多)

bash 复制代码
在/tmp目录下生成一个指定1G空间大小的文件(这个可不是空文件哟)
    '>>' dd if=/dev/zero of=/tmp/swapFile bs=1M count=1024 status=progress
            951058432字节(951 MB,907 MiB)已复制,3 s,315 MB/s
            记录了1024+0 的读入
            记录了1024+0 的写出
            1073741824字节(1.1 GB,1.0 GiB)已复制,3.80712 s,282 MB/s
    >> ls -lh /tmp | grep swapFile      ## 正好一个1G空间大小啊的文件
            -rw-r--r-- 1 root root 1.0G  1月 27 20:52 swapFile

二:实战操作

上面我们已经知道了dd命令的基本用法以及常用的参数了,下面我将带大家介绍dd在生产中的常见用法。

(一):数据转换

比如把文件里的大写字符转换为小写字符,或者把小写字符转大写;其实主要用到的是conv转换选项;

bash 复制代码
创建一个文件:
    >> echo "abcde_ABCDE_12345" > /mnt/sourceFile.txt
开始转换(把sourceFile.txt转换后存放到targetFile.txt)
    >> dd if=/mnt/sourceFile.txt of=/mnt/targetFile.txt conv=lcase
            记录了0+1 的读入
            记录了0+1 的写出
            18字节已复制,0.000306431 s,58.7 kB/s
    >> cat /mnt/targetFile.txt
            abcde_abcde_12345
说明:
    其实这个就是读取文件转换后输出到另外一个文件,具体conv请参看参数详解

(二):文件生成

有些场景需要生成大量的小文件或者大文件,而我们的文件系统一时无法找到那么多存在容量的指定大小文件,此时linux的dd命令就能快速的帮助你实现,这些大文件在swap交换空间里也能用的着;

bash 复制代码
生成一个10M大小的文件放在/tmp目录下:
    >> dd if=/dev/zero of=/tmp/testFile bs=1M count=10
            记录了10+0 的读入
            记录了10+0 的写出
            10485760字节(10 MB,10 MiB)已复制,0.0110062 s,953 MB/s
    >> ls -lh /tmp | grep testFile
            -rw-r--r-- 1 root root  10M  1月 27 21:32 testFile
    >> od /tmp/testFile     ## 查看文件内存了啥数据,被撑开10M空间
            0000000 000000 000000 000000 000000 000000 000000 000000 000000
            *
            50000000

在/opt目录下生成10个大小为2K空间的小文件
    >> seq 10 | xargs -i dd if=/dev/zero of=testDemo_{}.txt bs=1K count=2
            记录了2+0 的读入
            记录了2+0 的写出
            2048字节(2.0 kB,2.0 KiB)已复制,0.000187859 s,10.9 MB/s
            记录了2+0 的读入
            记录了2+0 的写出
            2048字节(2.0 kB,2.0 KiB)已复制,0.000158822 s,12.9 MB/s
            ....
    >> ls -lh /opt | grep 'testDemo_*'
            -rw-r--r-- 1 root root 2.0K  1月 27 21:44 testDemo_10.txt
            -rw-r--r-- 1 root root 2.0K  1月 27 21:44 testDemo_1.txt
            -rw-r--r-- 1 root root 2.0K  1月 27 21:44 testDemo_2.txt
            -rw-r--r-- 1 root root 2.0K  1月 27 21:44 testDemo_3.txt
            ....
关于/dev/zero:
    它是一个特殊的设备文件,会不断地产生字节值为零的数据流。
    /dev/zero通常被用于生成一个无限的字节流,其中所有的字节都是零。
'注:填充和磁盘分区同样大小的数据文件可以达到防止原来删除的数据被恢复的现象。'

(三):SWAP虚拟空间

在Linux中使用文件创建swap交换空间就可以使用到dd命令;

具体参考:写文章 - 实操Linux磁盘管理 【下】(SWAP、LVM、RAID) - 掘金 (juejin.cn)

(四):磁盘测速

dd还有一个重要的用途就是测试磁盘的读写速率了,它可以测试大文件读写和碎文件读写的时长和速率;我们可以通过这个方式测试,并将一些读写快的磁盘留给重要的应用或者swap交换空间。

bash 复制代码
测试磁盘的写速度:
    >> timeout 120 dd if=/dev/zero of=/tmp/speed.dat bs=2M count=1000 oflag=direct
            2097152000字节(2.1 GB,2.0 GiB)已复制,15 s,140 MB/s
            记录了1000+0 的读入
            记录了1000+0 的写出
            2097152000字节(2.1 GB,2.0 GiB)已复制,15.0006 s,140 MB/s
        (of文件只用于写,所以这个命令相当于测试磁盘的写能力;可以看出我的磁盘写的速度平均在140MB每秒)
测试磁盘的读速度:
    >> timeout 120 dd if=/tmp/speed.dat of=/dev/null bs=2M count=1000 status=progress
            记录了1000+0 的读入
            记录了1000+0 的写出
            2097152000字节(2.1 GB,2.0 GiB)已复制,0.308627 s,6.8 GB/s
        (可以看出我的磁盘读速度平均在6.8GB每秒)

说明:
    1:想观察具体读写进度可在后面加上:status=progress;
    2:timeout 120代表命令执行120秒还未执行完则自动停止超时;
    3:关于bs读写的字节数和count复制的次数可按照自己需求调整,从而测试读写速度;
        比如设置 bs=1K count=20000 代表测试碎文件的读写速度
    4:关于oflag选项请参数上面的参数详情

'关于/dev/zero:'
    它是一个特殊的设备文件,会不断地产生字节值为零的数据流。
    /dev/zero通常被用于生成一个无限的字节流,其中所有的字节都是零。
'关于/dev/null:'
    它是一个特殊的设备文件,它会丢弃所有写入到其中的数据,并立即返回成功。
    /dev/null通常被用于将输出或数据流重定向到一个空设备,实现数据丢弃的目的。

(五):制作U盘启动盘

dd命令还有个很实用的功能就是制作U盘启动盘,将U盘插入linux主机,然后使用命令 fdisk -l 查看U盘挂载的设备路径,假设这里U盘设备为/dev/sdb:

bash 复制代码
基本语法:
    sudo dd if=/***.iso of=/dev/xxx
        # if后接镜像文件路径
        # of后接写入U盘的路径
        # 可以利用watch -n 5每5s发送信号触发dd命令打印进度
将上传的镜像文件上传在linux目录后,执行如下命令制作U盘启动盘
    dd if=/home/ubuntu-23.10.1-desktop-amd64.iso of=/dev/sdb status=progress
    
'注:读取和写入的速度快慢可以调整bs和count这两个选项'

(六):备份主引导记录MBR

主引导记录(Master Boot Record,MBR),位于一个硬盘的0柱面、0盘面、1扇区,共512字节。具体划分依次为:引导代码区440字节、磁盘签名4字节、空白(Ox0000)2字节、MBR分区表(Disk Partition Table,DPT)64字节、结束标志(Ox55AA)2字节。其中的MBR分区表(DPT)区别于另一种"全局唯一标识分区表(GUID Partition Table,GPT)"。这里仅讨论MBR及DPT。

bash 复制代码
选择当前需要备份的磁盘MBR;这里我以vda来举例:
备份/恢复硬盘MBR(全部512字节):
    #备份#  dd if=/dev/vda of=/opt/mbr.bak bs=512 count=1
    #恢复#  dd if=/opt/mbr.bak of=/dev/vda bs=512 count=1
    说明:
        这里的bs代表一次读取或写入512字节;
        这里的count代表只复制一次,就是说明只读vda磁盘的前512字节就结束了
仅备份/恢复硬盘的分区表DPT(后66字节):
    #备份#  dd if=/dev/vda of=/opt/dpt.bak bs=1 skip=446 count=66
    #恢复#  dd if=/opt/dpt.bak of=/dev/vda bs=1 seek=446 count=66
    说明:
        因为DPT是在MBR里的,而DPT存在MBR里的第446字节开始往后数64字节结束,66是因为我算上了结束标志;
        bs代表每次读1字节,skip代表跳到第446字节开始读写,count代表复制66次
仅恢复硬盘MBR的引导代码部分(前446字节):
    #恢复#  dd if=/opt/mbr.bak of=/dev/vda bs=446 count=1
    说明:
        这个就是备份前446字节

用od查看备份的文件:od -Ax -x /opt/mbr.bak
    000000 63eb 0090 0000 0000 0000 0000 0000 0000
    000010 0000 0000 0000 0000 0000 0000 0000 0000
    *
    000050 0000 0000 0000 0000 0000 8000 0800 0000
    000060 0000 0000 faff 9090 c2f6 7480 f605 70c2
    000070 0274 80b2 79ea 007c 3100 8ec0 8ed8 bcd0
    000080 2000 a0fb 7c64 ff3c 0274 c288 bb52 0417
    000090 07f6 7403 be06 7d88 17e8 be01 7c05 41b4
    ....
相关推荐
鲁正杰30 分钟前
在一个服务器上抓取 Docker 镜像并在另一个服务器上运行
运维·服务器·docker
F-2H1 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
aherhuo1 小时前
基于openEuler22.09部署OpenStack Yoga云平台(一)
linux·运维·服务器·openstack
WebDeveloper20011 小时前
如何使用美国域名中心US Domain Center和WordPress创建商业网站
运维·服务器·css·网络·html
檀越剑指大厂1 小时前
【Linux系列】Shell 脚本中的条件判断:`[ ]`与`[[ ]]`的比较
linux·运维·服务器
2301_819287124 小时前
ce第六次作业
linux·运维·服务器·网络
CIb0la4 小时前
GitLab 停止为中国区用户提供 GitLab.com 账号服务
运维·网络·程序人生
武汉联从信息4 小时前
如何使用linux日志管理工具来管理oracle osb服务器日志文件?
linux·运维·服务器
天天进步20154 小时前
STUN服务器实现NAT穿透
运维·服务器
PieroPc4 小时前
Python 自动化 打开网站 填表登陆 例子
运维·python·自动化