Linux dd命令详解

dd 命令是一个功能强大的磁盘复制和转换工具,可以按块复制文件并进行数据转换。dd代表"数据复制器"(Data Duplicator),也被戏称为"磁盘破坏者"(Disk Destroyer),因为不当使用可能导致数据丢失。

重要警告

dd命令非常强大且危险! 错误的参数可能导致整个磁盘数据被覆盖。在使用dd命令前,务必仔细检查输入和输出参数,并确保已备份重要数据。

语法格式

dd [选项]
dd if=输入文件 of=输出文件 [bs=块大小] [count=块数] [skip=跳过块数] [seek=跳过块数] [conv=转换]

功能说明

  • 磁盘克隆:完整复制磁盘或分区
  • 备份恢复:创建磁盘镜像和从镜像恢复
  • 启动盘制作:将ISO镜像写入USB制作启动盘
  • 数据转换:转换文件格式、编码、大小写等
  • 测试性能:测试磁盘读写速度
  • 数据擦除:用特定数据覆盖磁盘空间
  • 文件截取:提取文件的部分内容

常用选项

选项 说明
if=文件 输入文件(input file),默认为标准输入
of=文件 输出文件(output file),默认为标准输出
bs=字节 同时设置输入和输出的块大小(block size)
ibs=字节 输入块大小(input block size)
obs=字节 输出块大小(output block size)
count=块数 只复制指定数量的块
skip=块数 从输入文件开头跳过指定数量的块
seek=块数 从输出文件开头跳过指定数量的块
conv=转换 转换参数,多个用逗号分隔
status=级别 显示进度信息:none, noxfer, progress

conv转换参数

转换参数 说明
ascii 将EBCDIC转换为ASCII
ebcdic 将ASCII转换为EBCDIC
ibm 将ASCII转换为alternate EBCDIC
block 将换行符替换为指定长度的空格
unblock 将指定长度的空格替换为换行符
lcase 将大写字母转换为小写
ucase 将小写字母转换为大写
sparse 创建稀疏文件(节省空间)
swab 交换每对字节
sync 将每个输入块填充到ibs大小
excl 如果输出文件已存在则失败
nocreat 不创建输出文件
notrunc 不截断输出文件
noerror 读取错误时继续处理

使用示例

示例1:基本文件复制

# 复制文件
dd if=source.txt of=destination.txt

# 复制文件并显示进度
dd if=source.txt of=destination.txt status=progress

# 指定块大小复制(4K块)
dd if=source.txt of=destination.txt bs=4k

示例2:制作启动U盘

警告:以下命令会完全擦除USB设备上的所有数据!请确认设备路径正确。
# 1. 查看USB设备路径
sudo fdisk -l
# 通常USB设备是/dev/sdb或/dev/sdc,确认你的USB设备路径

# 2. 卸载USB设备(如果已挂载)
sudo umount /dev/sdb*

# 3. 写入ISO镜像到USB
sudo dd if=ubuntu-22.04.iso of=/dev/sdb bs=4M status=progress

# 4. 同步数据确保写入完成
sync

示例3:磁盘克隆(完整备份)

危险操作:以下命令可能破坏数据,确保设备路径正确且已备份重要数据。
# 磁盘到磁盘克隆(源盘和目标盘大小应相同或目标更大)
sudo dd if=/dev/sda of=/dev/sdb bs=64K status=progress

# 磁盘到镜像文件备份
sudo dd if=/dev/sda of=/backup/disk.img bs=64K status=progress

# 压缩备份(节省空间)
sudo dd if=/dev/sda bs=64K | gzip > /backup/disk.img.gz

# 从镜像恢复磁盘
sudo dd if=/backup/disk.img of=/dev/sda bs=64K status=progress

# 解压缩恢复
gunzip -c /backup/disk.img.gz | sudo dd of=/dev/sda bs=64K

示例4:分区备份与恢复

# 备份分区到文件
sudo dd if=/dev/sda1 of=/backup/sda1.img bs=4M status=progress

# 恢复分区
sudo dd if=/backup/sda1.img of=/dev/sda1 bs=4M status=progress

# 备份MBR(前512字节)
sudo dd if=/dev/sda of=/backup/mbr.bak bs=512 count=1

# 恢复MBR
sudo dd if=/backup/mbr.bak of=/dev/sda bs=512 count=1

# 备份分区表(MBR的前446字节是引导代码,接着64字节是分区表)
sudo dd if=/dev/sda of=/backup/partition-table.bak bs=1 count=64 skip=446

示例5:数据擦除和安全删除

# 用零填充磁盘(快速擦除)
sudo dd if=/dev/zero of=/dev/sdb bs=1M status=progress

# 用随机数据填充磁盘(安全擦除)
sudo dd if=/dev/urandom of=/dev/sdb bs=1M status=progress

# 多次覆盖擦除(更安全)
for i in {1..3}; do
    echo "第 $i 次覆盖..."
    sudo dd if=/dev/urandom of=/dev/sdb bs=1M status=progress
done

# 擦除文件内容(不删除文件)
dd if=/dev/urandom of=secret-file.txt bs=1M count=10
# 然后删除文件
rm secret-file.txt

示例6:磁盘性能测试

# 测试写入速度(1GB测试文件)
dd if=/dev/zero of=testfile bs=1G count=1 oflag=direct

# 测试读取速度
dd if=testfile of=/dev/null bs=1G count=1 iflag=direct

# 测试同时读写
dd if=testfile of=testfile2 bs=1G count=1

# 使用不同块大小测试
for bs in 1k 4k 16k 64k 256k 1M 4M; do
    echo "测试块大小: $bs"
    dd if=/dev/zero of=testfile bs=$bs count=1000 2>&1 | grep -E "(copied|MB/s)"
    rm testfile
done

示例7:数据转换和处理

# 转换文件大小写
dd if=input.txt of=uppercase.txt conv=ucase
dd if=input.txt of=lowercase.txt conv=lcase

# 创建稀疏文件(节省空间)
dd if=/dev/zero of=sparse-file.img bs=1 count=0 seek=1G

# 交换字节顺序
dd if=input.bin of=swapped.bin conv=swab

# 提取文件的部分内容
dd if=largefile.bin of=part.bin bs=1M skip=100 count=50  # 跳过前100MB,提取50MB

# 创建特定大小的文件
dd if=/dev/zero of=1gbfile.bin bs=1M count=1024  # 创建1GB文件
dd if=/dev/urandom of=random-100M.bin bs=1M count=100  # 创建100MB随机文件

示例8:高级用法和脚本

#!/bin/bash
# 备份脚本示例

BACKUP_DIR="/backup"
DISK="/dev/sda"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$BACKUP_DIR/backup_$DATE.log"

log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

backup_mbr() {
    log_message "备份MBR..."
    sudo dd if=$DISK of="$BACKUP_DIR/mbr_$DATE.bak" bs=512 count=1 2>> "$LOG_FILE"
    if [ $? -eq 0 ]; then
        log_message "MBR备份成功"
    else
        log_message "MBR备份失败"
        return 1
    fi
}

backup_partition() {
    local partition=$1
    log_message "备份分区 $partition..."

    # 检查分区是否存在
    if [ ! -b "$partition" ]; then
        log_message "分区 $partition 不存在"
        return 1
    fi

    local part_name=$(basename "$partition")
    local backup_file="$BACKUP_DIR/${part_name}_$DATE.img"

    # 开始备份
    sudo dd if="$partition" of="$backup_file" bs=4M status=progress 2>&1 | tee -a "$LOG_FILE"

    # 验证备份文件
    if [ -f "$backup_file" ] && [ $(stat -c%s "$backup_file") -gt 0 ]; then
        log_message "分区 $partition 备份成功: $backup_file"

        # 压缩备份文件
        log_message "压缩备份文件..."
        gzip "$backup_file"

        # 计算压缩率
        original_size=$(stat -c%s "$backup_file.gz")
        log_message "备份完成,文件大小: $(du -h "$backup_file.gz" | cut -f1)"
    else
        log_message "分区 $partition 备份失败"
        return 1
    fi
}

# 主程序
main() {
    log_message "开始系统备份"

    # 创建备份目录
    mkdir -p "$BACKUP_DIR"

    # 备份MBR
    backup_mbr

    # 备份关键分区
    backup_partition "/dev/sda1"  # 假设sda1是boot分区
    backup_partition "/dev/sda2"  # 假设sda2是root分区

    log_message "系统备份完成"
    echo "备份日志: $LOG_FILE"
}

main "$@"

进度查看技巧

方法1:使用status参数

dd命令自带的进度显示:

dd if=/dev/sda of=/dev/sdb bs=4M status=progress
方法2:使用pv命令

通过管道使用pv显示进度:

sudo dd if=/dev/sda bs=4M | pv | sudo dd of=/dev/sdb bs=4M
方法3:发送USR1信号

在另一个终端查看进度:

# 运行dd命令
sudo dd if=/dev/sda of=/dev/sdb bs=4M &

# 查看dd进程ID
ps aux | grep dd

# 发送USR1信号查看进度
kill -USR1 进程ID
方法4:使用watch命令

监控输出文件大小:

# 在一个终端运行dd
sudo dd if=/dev/sda of=disk.img bs=4M

# 在另一个终端监控文件大小
watch -n 1 'ls -lh disk.img'

常见错误和注意事项

问题描述:错误的设备路径可能导致重要数据被覆盖。

预防措施:

  1. 使用lsblkfdisk -l确认设备路径
  2. 多次检查if和of参数
  3. 在关键操作前先备份数据
  4. 使用oflag=sync确保数据完全写入
# 正确做法:先检查设备
lsblk
sudo fdisk -l

# 确认无误后再执行
sudo dd if=ubuntu.iso of=/dev/sdb bs=4M status=progress

问题描述:dd命令默认不显示进度,长时间操作时无法了解进度。

解决方案:

  1. 使用status=progress参数
  2. 使用pv命令显示进度
  3. 在另一个终端发送USR1信号
# 方法1:使用status参数
dd if=/dev/sda of=/dev/sdb bs=4M status=progress

# 方法2:使用pv
sudo dd if=/dev/sda bs=4M | pv -s $(sudo blockdev --getsize64 /dev/sda) | sudo dd of=/dev/sdb bs=4M

# 方法3:发送信号(在另一个终端)
kill -USR1 $(pidof dd)

问题描述:创建镜像时目标磁盘空间不足。

解决方案:

  1. 检查目标磁盘空间:df -h
  2. 使用压缩备份:dd if=/dev/sda | gzip > backup.img.gz
  3. 使用稀疏文件:dd if=/dev/sda of=backup.img conv=sparse
  4. 只备份使用的空间:使用partclone等工具
# 压缩备份节省空间
sudo dd if=/dev/sda bs=4M | gzip -c > /backup/disk.img.gz

# 稀疏文件(仅限某些文件系统)
sudo dd if=/dev/sda of=/backup/disk.img conv=sparse

# 只备份使用的块(需要文件系统支持)
sudo partclone.ext4 -c -s /dev/sda1 -o /backup/sda1.partclone.img

注意事项

  • 数据安全:dd命令不会询问确认,错误的参数会立即执行
  • 设备权限:操作磁盘设备需要root权限
  • 进度监控:长时间操作时使用进度监控功能
  • 块大小优化:合适的块大小能提高性能(通常4M-64M)
  • 数据同步:操作完成后使用sync命令确保数据写入
  • 错误处理:使用conv=noerror忽略读取错误继续
  • 大小写敏感:参数必须小写(if, of, bs等)
  • 路径检查:操作前多次检查设备路径
  • 备份验证:备份后验证文件完整性

相关命令

  • cp - 复制文件和目录
  • cat - 连接文件并打印到标准输出
  • pv - 管道查看器,显示数据传输进度
  • rsync - 远程同步文件
  • gzip - 压缩/解压缩文件
  • fdisk - 磁盘分区工具
  • mkfs - 创建文件系统
  • partclone - 分区备份工具