来源:马哥Linux运维 | 发布日期:2026-06-09
Linux rm -rf 误删文件恢复实战指南
适用场景: Linux 服务器上因
rm -rf、find -exec rm等操作误删文件后的应急响应与数据恢复。覆盖 ext4/xfs/btrfs/ZFS 四大文件系统,含 LVM 快照、dd 镜像、lsof 抢救等多种手段,以及防误删的制度和工程实践。本文的所有破坏性操作(dd、mkfs、umount、lvremove 等)均需在测试机或快照上演练,生产环境必须有变更审批和回滚预案。
一、事故复盘:rm -rf 是怎么敲下去的
某公司备份服务器在凌晨 02:17 发生了一起典型的 rm -rf 误删事故。这台机器承接应用层每天 02:00 的 mysqldump 输出,通过 rsync 推送到异地机房——典型的"用着没出过事、所以半年没巡检"的状态。
上一任运维留下的清理脚本 cleanup.sh 中有一行核心逻辑:
find -L /data/backup -type d -mtime +30 -exec rm -rf {} \;
新任运维小 A 接手后做了一次目录重构,把 /data/backup 拆成了 mysql/、app/、logs/、tmp/ 四个子目录。他改了 cleanup.sh 里的路径,把 /data/backup 改成了 /data/backup/tmp——因为他觉得临时目录总归要清。但这一步没有经过 Code Review,也没有在预发环境演练过。
致命陷阱: /data/backup/tmp 是一个指向父目录 /data/backup 的软链——上一任运维为了偷懒创建的。find -L 主动跟随软链,结果把整个 /data/backup 当成"临时目录"展开去清理了。/data/backup/mysql(mysqldump 文件)和 /data/backup/app(应用归档包)全部被删,/data/backup/logs 因为被后台进程打开了几个文件(rm 删掉了硬链接但 inode 还在进程手上),看起来"还在"实际也是假象。
02:30,异地机房的 rsync 接收端三次推送失败,告警升级到 P1。
关键教训: 目录重构后清理脚本的路径指向必须经过 Code Review;清理脚本必须带 dry-run 模式先演练;find -L 配合 -exec rm 需要加软链限制;目录迁移后必须验证软链指向的合理性。
二、为什么 rm -rf 几乎不可逆
2.1 Linux 文件删除的本质
很多新人以为 rm -rf 跟 Windows 的"Shift + Delete"差不多,实际上差异巨大。Linux 下"删除一个文件"并不是把磁盘上的字节清零,而是做三件事:
- 把目录项(dentry)从父目录的目录树里摘掉
- 把文件的链接计数(link count)减 1
- 如果链接计数降到 0,文件变为"unlinked"状态,等待被回收
只有当文件 unlinked 且没有被任何进程持有(open file count = 0)时,内核才会把这个 inode 释放回 inode 位图。inode 被释放后,对应的磁盘块才会被标记为 free,加入到空闲块池里,等待被新数据覆写。
所以"删除"只动了 inode 和目录项的元数据,磁盘上的实际数据是完整保留的——直到被新数据覆盖。
2.2 ext4 下的删除动作
以 ext4 为例,rm -rf 在 VFS 层依次触发:
vfs_unlink / vfs_rmdir
→ ext4_unlink / ext4_rmdir
→ ext4_delete_entry(删目录项)
→ ext4_dec_count(链接计数 -1)
→ 如果是文件:调用 ext4_free_inode_after_ordered,把 inode 标为 free
→ 把对应的 block 标为 free
关键点: ext4 在删除时只是把 block 标记为空闲,并不会清零 block 内容。所以只要 block 没被新数据覆盖,理论上就能恢复。
2.3 xfs 的差异
xfs 的元数据布局跟 ext4 完全不同:
- xfs 使用 B+ 树管理 inode(AGI)和 block(AGF)
- xfs 的目录项存放在 dir2 格式中,删除动作比 ext4 更复杂
- xfs 在删除大文件时,extent 分配器会很快把 block 标记为 free,但不会清零
- xfs 的日志(xlog)相对激进,元数据修改会先写日志
业界流传的说法是"xfs 删了就没了,ext4 还能救"——不严谨,但方向对:xfs 的恢复工具少、效果差;ext4 的恢复工具链成熟(extundelete、debugfs、testdisk)。
2.4 为什么不能 100% 恢复
即使文件系统保留 block 不清零,以下情况仍会导致恢复失败:
| 场景 | 原因 |
|---|---|
| 块已被新数据覆盖 | 内核把 block 分配给新文件 |
| journal 重放 | ext4 的日志回放可能修改元数据 |
| 文件被 truncate 后再写入 | 恢复出来的是空洞 + 后续覆盖数据 |
| 文件严重碎片化 | 恢复出来的 block 顺序可能错乱 |
| 文件名丢失 | 很多工具只能按 inode 恢复,文件名无法对应 |
| CoW 文件系统(btrfs/zfs)无 snapshot | 没有备份点就同 ext4 一样看运气 |
核心原则: "恢复"是抢救,不是保证。恢复出来的文件可能名称变成
inode_12345.dump、内容部分损坏(特别是被部分覆盖的)、大文件中间缺块、压缩包校验失败。这些风险必须在动手前就跟业务方讲清楚。
三、事故响应的第一秒:先止血
误删后最危险的直觉是"马上动手救"。正确的第一反应:
3.1 保持现状,不要重启
- ❌ 不要
reboot、init 6、shutdown -r now - ❌ 不要
sync(可能触发脏页回写) - ❌ 不要
kill -9你以为"无关"的进程
3.2 立即隔离写流量
# 停 cron,避免 cleanup 脚本二次执行
systemctl stop crond
# 停掉可能写该目录的应用进程
systemctl stop mysqld # 示例:如果 MySQL 写该目录
四、止血三板斧
4.1 设为只读(最有效)
# 找到挂载点对应的设备
df /data/backup
# 输出:/dev/sdb1 50G 30G 18G 63% /data
# 重新挂载为只读
mount -o remount,ro /data
# 验证
mount | grep /data
# 应显示:/dev/sdb1 on /data type ext4 (ro,...)
# 更安全的块设备层只读(不触发写回)
blockdev --setro /dev/sdb1
4.2 LVM 快照(工业级首选)
# 查看 VG 剩余空间
vgdisplay | grep -E "VG Name|Free"
# 创建快照
lvcreate -s -L 10G -n data_snap_20260609 /dev/vg0/data
# 挂载快照(只读)
mkdir -p /mnt/snap
mount -o ro /dev/vg0/data_snap_20260609 /mnt/snap
# 在快照上做恢复实验
ls -la /mnt/snap/data/backup/mysql/
LVM 快照的原理是 COW(Copy-on-Write):快照创建后,对原 LV 的写操作把原数据复制到快照空间,快照数据保持创建那一刻的视图。
4.3 dd 磁盘镜像(无 LVM 时的兜底)
# 找一块至少同样大的目标盘
lsblk
# 做全盘镜像
dd if=/dev/sdb of=/dev/sdc bs=4M status=progress conv=noerror,sync
# 验证镜像
md5sum /dev/sdb
md5sum /dev/sdc
⚠️
dd误把 of 写错是真实存在的灾难,务必三遍确认。建议加oflag=direct绕过 page cache。
4.4 lsof 抢救(进程还持有文件时)
rm -rf 删除了目录项,但只要有进程还 open 着这个文件,内核就不会真的释放 inode 和 block。这是恢复成本最低的路径——不需要任何文件系统级别的工具。
# 找出所有 /data/backup 下的打开文件(link count <= 1)
lsof +L1 /data/backup
# 也可以直接搜 deleted 标记
lsof | grep deleted
# 输出形如:
# mysqld 1234 mysql 8w REG 8,1 1048576 12345 /data/backup/mysql/dump.sql (deleted)
# 找到 PID 和 FD
ls -la /proc/1234/fd/8
# lrwx------. 1 mysql mysql 64 Jun 9 02:17 /proc/1234/fd/8 -> /data/backup/mysql/dump.sql (deleted)
# 直接 cp 出来(最安全的恢复方式)
cp /proc/1234/fd/8 /tmp/recovered_dump_20260608.sql
高级技巧——批量恢复所有 deleted 文件:
#!/bin/bash
# 批量恢复 lsof 发现的 deleted 文件
OUT_DIR="/mnt/recovery/lsof_recovered"
mkdir -p "$OUT_DIR"
lsof | grep deleted | grep "/data/backup" | \
awk '{print $2, $4, $NF}' | \
while read pid fd name; do
fd_num=$(echo "$fd" | sed 's/[a-z]//')
target="$OUT_DIR/$(basename $name).pid${pid}"
cp "/proc/$pid/fd/$fd_num" "$target" 2>/dev/null && \
echo "Recovered: $target"
done
五、评估能否恢复
正式恢复前,用这份 7 步调查清单摸清环境。这一步不能跳过——它直接决定了该用哪个恢复方案:
# 1. 确认文件系统类型
blkid /dev/sdb1
# 2. 确认挂载选项
findmnt /data
# 特别注意 relatime/strictatime/noatime——如果是 noatime,
# inode 上的 i_atime 不会被更新,恢复时能看到更准确的访问时间
# 3. 确认磁盘是否还有大量写入
iostat -dx 1 5
# 看 %util 和 w/s。如果 w/s 持续 > 0,说明有进程在写,
# 越早止血越重要
# 4. 磁盘健康度
smartctl -H /dev/sdb
# 如果磁盘本身有坏道,恢复成功率会显著下降
# 5. 磁盘空间与 inode 使用率
df -h /data
df -i /data
# ext4 上即使磁盘空间够,inode 满了也无法创建文件
# 6. 文件系统是否已损坏(只读检查)
fsck -n /dev/sdb1 # ext4
xfs_repair -n /dev/sdb1 # xfs
# -n 表示只读检查,不修。这步是"诊断",不是"治疗"
# 7. 内核日志
dmesg | tail -100
journalctl -k -p err --since "1 hour ago"
# 如果看到 EXT4-fs error、I/O error、Buffer I/O error,
# 说明磁盘或 FS 本身有健康问题
关键判断: 确认文件系统类型后,才能选择正确的恢复工具。ext4 首选 extundelete,xfs 需要 xfs_undelete(效果一般),btrfs/zfs 优先看快照。
六、恢复方案详解
方案 A:ext4 + extundelete(首选)
extundelete 是 ext 系列文件系统的首选恢复工具。
安装:
# CentOS/RHEL
yum install -y epel-release
yum install -y extundelete
# Ubuntu/Debian
apt-get install -y extundelete
注意事项——路径是新人最容易踩的坑:
extundelete 接收的路径是 FS 根相对路径(去掉挂载点前缀)。如果 /dev/sdb1 挂在 /data,文件 OS 路径是 /data/backup/mysql/dump.sql,那么 extundelete 接收的路径必须是 /backup/mysql/dump.sql。
# 1. 先把 FS 设为只读
mount -o remount,ro /data
# 2. 恢复结果输出到独立磁盘(不能写回原盘)
mkdir -p /mnt/recovery
mount /dev/sdc1 /mnt/recovery
# 3. 恢复指定文件
extundelete /dev/sdb1 --restore-file /backup/mysql/dump_20260608.sql
# 4. 恢复整个目录
extundelete /dev/sdb1 --restore-directory /backup/mysql
# 5. 按时间窗口恢复
extundelete /dev/sdb1 --restore-all --before "2026-06-09 00:00:00"
# 6. 扫描所有可恢复文件(先列出)
extundelete /dev/sdb1 --list-all > /tmp/extundelete_list.txt
常见坑:
| 问题 | 原因 | 解决 |
|---|---|---|
| 恢复结果为空 | 路径带了挂载点前缀 | 先 --list-all 看目录树,复制 FS 相对路径 |
| can't find ext3 journal | extundelete 版本与内核不兼容 | CentOS 7 正常,RHEL 8 上有问题;建议源码编译 |
| 恢复文件 size=0 | inode i_size 被覆写 |
用 debugfs 按 inode 读取(见方案 B) |
文件名变成 inode_NNNN |
目录项丢失 | 按 inode 对应原文件名;--list-all 能看到文件名和 inode 的映射 |
验证恢复结果:
# 1. 数量对比
find RECOVERED_FILES/ -type f | wc -l
# 2. 大文件检查
ls -lS RECOVERED_FILES/ | head -20
# 3. 文件类型识别
file RECOVERED_FILES/*
# 4. 抽样校验
md5sum RECOVERED_FILES/mysql/dump_20260608.sql
# 跟应用方确认的预期值对比
方案 B:ext4 + debugfs(精细化恢复)
进入 debugfs:
# 只读模式进入(务必加 -c,否则默认 write 模式可能修改 FS)
debugfs -c /dev/sdb1
# 进入交互后:
# 列出 unlinked 的 inode
debugfs: lsdel
# 输出每个 unlinked inode 的 owner、size、dtime、block 等信息
# 查看 inode 内容
debugfs: stat <12345>
# 把 inode 内容 dump 出来
debugfs: dump <12346> /mnt/recovery/dump_recovered.sql
# 列出目录下的所有项(包括 deleted)
debugfs: ls -l /data/backup/mysql
# 退出
debugfs: quit
——debugfs 的目录树展示非常详细,一一翻阅很花时间,建议先定向到文件分析
8.3 列出所有 unlinked 的 inode(关键步骤)
debugfs: lsdel
# 输出每个 unlinked inode 的 owner、size、dtime、block 等信息
lsdel 输出的是已经被删除但 inode 尚未被重新分配的记录。每个记录包含 inode 号、文件大小、删除时间(dtime)和占用的 block 数。通过这个列表可以确定哪些 inode 还有恢复价值。
8.4 实战:按 inode 恢复被删文件
# 如果有历史 ls -i 输出或聊天记录里有 inode 号
ls -i /data/backup/mysql # 已删除目录上跑不了,需从历史拿
# 批量 dump
for ino in 12346 12347 12348; do
debugfs -c /dev/sdb1 -R "dump <${ino}> /mnt/recovery/inode_${ino}.dump"
done
方案 C:xfs 恢复
xfs 的恢复成功率远低于 ext4,主流方案效果一般。认可度较高的说法是"xfs 删了就没了,ext4 还能救"——不严谨,但方向对。xfs 使用 B+ 树管理 inode(AGI)和 block(AGF),日志(xlog)相对激进,恢复工具少。
方案 D:testdisk + photorec(无差别按块扫)
适用于文件系统结构严重损坏的场景:
# 安装
yum install -y testdisk # CentOS
apt-get install -y testdisk # Ubuntu
# 启动 testdisk(交互式)
testdisk /dev/sdb
# 启动 photorec(扫描文件类型)
photorec /dev/sdb
testdisk 恢复已删除文件的操作路径:选择 [Create] 创建日志 → 选择磁盘 → 选择分区表类型 → 选择 [Undelete] → 选择目标目录。
photorec 按文件类型签名扫描,不依赖文件系统结构,适合严重损坏的场景。
方案 E:lsof 抢救未关闭文件(成本最低)
参考 4.4 节。如果误删后相关进程尚未重启,通过 /proc/PID/fd/N 直接 cp 出来。这是所有恢复方案中成本最低、成功率最高的路径——前提是进程还没重启。
每个打开的文件描述符在 /proc 文件系统中是一个符号链接,rm -rf 只删除了目录项的硬链接,文件内容仍在磁盘上,进程仍可读写。只要不做以下操作,数据就保得住:
- ❌ 重启进程(会关闭 fd,内核释放 inode)
- ❌
systemctl restart相关服务 - ❌ 杀死持有 fd 的进程后未先复制数据
方案 F:LVM / ZFS / btrfs 快照回滚(成功率最高)
如果有近期快照,这是恢复成功率最高的方案:
# LVM 快照(参考 4.2 节)挂载后直接 cp
cp -a /mnt/snap/data/backup/mysql/ /mnt/recovery/
# btrfs 子卷快照
btrfs subvolume list /data
btrfs subvolume snapshot /data /data/.snapshots/recover_20260609
# btrfs 访问快照
ls /data/.zfs/snapshot/recover_2026-06-09_021800/data/backup/mysql/
# ZFS 快照
zfs list -t snapshot | grep data
zfs snapshot data@recover_20260609
ls /data/.zfs/snapshot/recover_20260609/data/backup/mysql/
七、实战时间线:一次完整的误删恢复全过程
把前面讲的工具串起来,按真实事故的时间线给一个完整流程。假设场景中凌晨 02:17 误删了 /data/backup/mysql/ 和 /data/backup/app/,文件系统为 ext4,已做 LVM。
02:17 — 接告警
接手告警后,ssh 到目标机,先停手观察,不做任何修改操作。
# 确认现象
ls /data/backup/mysql/ # 为空
df /data/backup # 记录磁盘状态
02:20 — 止血
# 停 cron
systemctl stop crond
systemctl mask crond
# 停 mysqld(防止写数据)
systemctl stop mysqld
# LVM 快照
lvcreate -s -L 20G -n data_snap_recovery /dev/vg0/data
# 挂载快照
mkdir -p /mnt/snap
mount -o ro /dev/vg0/data_snap_recovery /mnt/snap
02:25 — 抢救进程持有文件
lsof | grep deleted | grep "/data/backup" > /tmp/deleted_files.txt
# 收集所有 fd 中的文件
mkdir -p /mnt/recovery/lsof_save
for pid_fd in $(awk '{print $2"/fd/"$4}' /tmp/deleted_files.txt | sed 's/[a-z]//'); do
cp "/proc/$pid_fd" /mnt/recovery/lsof_save/ 2>/dev/null
done
02:35 — 评估环境
blkid /dev/sdb1 # ext4
smartctl -H /dev/sdb # 健康
dmesg | tail -20 # 无 IO 错误
02:40 — 准备恢复
mkdir -p /mnt/recovery
mount /dev/sdc1 /mnt/recovery # 独立目标盘
mount -o remount,ro /data # 原盘设为只读
02:45 — extundelete 恢复
extundelete /dev/sdb1 --restore-directory /backup/mysql \
--output-dir /mnt/recovery/extundelete_out
03:10 — 验证
# 核对文件数量
find /mnt/recovery/extundelete_out -type f | wc -l
# 大文件检查
ls -lhS /mnt/recovery/extundelete_out/ | head -10
# 抽样校验
md5sum /mnt/recovery/extundelete_out/backup/mysql/dump_20260608.sql
# 加载到测试库验证
mysql -u root -p -e "source /mnt/recovery/extundelete_out/backup/mysql/dump_20260608.sql"
04:00 — 交付
将恢复数据 rsync 到目标位置,通知应用方做端到端校验。确认无误后记录复盘文档。
八、验证恢复结果
# 1. 数量对比
find RECOVERED_FILES/ -type f | wc -l
# 2. 大文件检查
ls -lS RECOVERED_FILES/ | head -20
# 3. 文件类型识别
file RECOVERED_FILES/*
# 4. 抽样校验
md5sum RECOVERED_FILES/mysql/dump_20260608.sql
# 5. 业务校验——让应用方做端到端确认
九、防误删工程体系
9.1 制度层
清理脚本 Code Review 制度: 任何 find ... -exec rm、rm -rf、shred 等破坏性命令,必须经过 Code Review、必须带 dry-run、必须有时间范围判断。
清理脚本 dry-run 模板:
#!/bin/bash
# cleanup.sh — 清理 30 天前的旧备份
DRY_RUN=${DRY_RUN:-1} # 默认 dry-run(安全模式)
LOG_FILE=${LOG_FILE:-/var/log/cleanup.log}
log() {
echo "$(date '+%F %T') $*" | tee -a "$LOG_FILE"
}
if [ "$DRY_RUN" = "1" ]; then
log "DRY-RUN: would remove the following:"
find /data/backup/mysql -type f -mtime +30 -print
exit 0
fi
# 真正的清理逻辑
log "REAL-CLEAN: starting"
find /data/backup/mysql -type f -mtime +30 -print -delete
log "REAL-CLEAN: done"
强制二次确认脚本:
#!/bin/bash
# rm_with_confirm.sh
TARGET="$1"
if [ -z "$TARGET" ]; then
echo "Usage: $0 <path>"
exit 1
fi
echo "==== WARNING ===="
echo "About to remove: $TARGET"
echo "Resolved path: $(readlink -f "$TARGET")"
echo "Disk usage: $(du -sh "$TARGET" 2>/dev/null | awk '{print $1}')"
echo "==== END ===="
read -p "Type 'YES' to continue: " confirm
if [ "$confirm" != "YES" ]; then
echo "Aborted."
exit 1
fi
rm -rf -- "$TARGET"
echo "Removed."
9.2 命令层
用 trash-cli 替换 rm:
# 安装
pip3 install trash-cli
# 使用
trash-put foo.txt # 移动到回收站
trash-list # 列出回收站
trash-restore foo.txt # 恢复
trash-empty # 清空回收站
# 替换 alias
alias rm='trash-put'
安全原则:
find ... -exec rm配合软链非常危险,-L会跟随软链扩大删除范围- 优先用
find ... -delete(find 内置,不执行外部命令,攻击面小) - 通配符删除时先
ls确认再删 - 可以考虑
safe-rm在/etc/safe-rm.conf中配置黑名单路径
9.3 备份层:3-2-1 策略 + 自动快照
3-2-1 备份策略:
- 3 份副本(本地 LVM snapshot + 异地 rsync + 对象存储)
- 2 种介质
- 1 份异地
LVM 自动快照脚本(每天凌晨 2 点,保留 7 天):
#!/bin/bash
# daily_snapshot.sh
VG_NAME=vg0
LV_NAME=data
SNAP_SIZE=20G
KEEP_DAYS=7
SNAP_PREFIX=data_daily
# 1. 创建快照
DATE=$(date +%Y%m%d)
SNAP_NAME="${SNAP_PREFIX}_${DATE}"
lvcreate -s -L ${SNAP_SIZE} -n ${SNAP_NAME} /dev/${VG_NAME}/${LV_NAME}
# 2. 删除过期快照
for old_snap in $(lvs --noheadings -o lv_name ${VG_NAME} | grep "${SNAP_PREFIX}"); do
snap_date=$(echo $old_snap | grep -oP '\d{8}')
if [ -n "$snap_date" ] && [ $(( ($(date +%s) - $(date -d "$snap_date" +%s)) / 86400 )) -gt $KEEP_DAYS ]; then
lvremove -f /dev/${VG_NAME}/${old_snap}
fi
done
十、复盘总结
给初中级运维的建议
事故复盘是一线运维的"软基建"。这次事故的复盘,真正落地了以下几件事:
- 清理脚本的改造: 全部加上
DRY_RUN模式,默认不执行;路径改为绝对路径+readlink 验证;find ... -exec rm改为find ... -delete(内置执行,避免软链攻击) - 目录重构流程卡: 所有涉及路径变更的操作,必须更新存量脚本中的硬编码路径,并在 pre-commit hook 中加 grep 检查
- 软链审计: 生产环境禁止父目录回环软链;如有
tmp -> .或tmp -> ..等模式,必须清除 - 日常 snapshot 制度化: 对关键目录启用 LVM 快照或云盘快照,保留 7 天自动轮转
- 监控增强: 增加对"目录文件数突降"的告警,避免凌晨误删后无人知晓
推荐阅读与工具
文档:
- ext2fsprogs 文档:debugfs、e2fsck、mke2fs 的官方手册
- LVM 官方文档(Red Hat):理解 snapshot 实现
- BTRFS Wiki:理解 CoW 文件系统
- ZFS 文档:理解
zfs send/receive
工具:
| 工具 | 用途 | 获取方式 |
|---|---|---|
| extundelete | ext4 文件恢复首选 | EPEL / 源码 (sf.net) |
| testdisk | 交互式恢复 | epel / cgsecurity.org |
| photorec | 按文件类型签名恢复 | 同 testdisk |
| sleuthkit | 文件系统法医分析 | sleuthkit.org |
| ddrescue | 磁盘镜像(带坏道处理) | gnu.org |
| trash-cli | rm 替代回收站 | pip3 / github |
结语
rm -rf 不可怕,可怕的是"以为自己有备份所以不担心"。做运维越久,越会敬畏"删除"这个动作:它不像写,写错了能 git revert;它更像 DROP TABLE,跑完就没了。
技术会变,ext4 会变成 btrfs,CentOS 会变成 Rocky,rm 会被各种 wrapper 包装。但"删除"这件事的本质不会变:它永远是不可逆的、永远需要审批的、永远需要备份的。
十二、风险点与不可恢复场景
以下场景恢复工具基本救不回来,需提前认清:
| 场景 | 原因 |
|---|---|
| 数据已被覆盖多次 | block 被新数据覆写 |
| 磁盘使用率极高(>95%) | inode 和 block 被快速重新分配 |
| 文件系统被格式化 | mkfs 重建了整个元数据 |
使用 shred 或 wipe 删除 |
主动覆写了数据 |
| SSD 的 TRIM 已触发 | 块设备返回全零 |
| 误删后大量写入已发生 | 新数据覆盖了空闲块 |
| 文件系统为 zfs/btrfs 但无 snapshot | CoW 文件系统的行为差异 |
十三、应急工具包与一键脚本
以下命令打包为快速响应脚本 recovery_first_aid.sh:
#!/bin/bash
# recovery_first_aid.sh — 误删应急响应的第一套命令
# 使用方法:source recovery_first_aid.sh,会自动采集现场信息
# 1. 时间记录
date > /tmp/recovery_timeline.txt
uptime >> /tmp/recovery_timeline.txt
# 2. 磁盘状态
df -h > /tmp/disk_usage.txt
df -i > /tmp/inode_usage.txt
# 3. 内存
free -h > /tmp/memory.txt
# 4. 进程列表
ps aux > /tmp/process_list.txt
# 5. 已挂载文件系统
mount > /tmp/mount_info.txt
# 6. 打开的文件描述符(重要——可能还有活口)
lsof +L1 /data/backup > /tmp/deleted_open_files.txt 2>/dev/null
lsof | grep deleted >> /tmp/deleted_open_files.txt 2>/dev/null
# 7. 文件系统类型
blkid > /tmp/blkid.txt
file -s /dev/sdb1 >> /tmp/blkid.txt
# 8. 内核日志
dmesg > /tmp/dmesg.txt
journalctl -k -p err --since "1 hour ago" > /tmp/journal_err.txt 2>/dev/null
echo "现场信息已收集到 /tmp/ 下,文件名列表:"
ls -la /tmp/recovery_*.txt /tmp/deleted_open_files.txt /tmp/disk_usage.txt 2>/dev/null
十四、附录:应急响应 SOP 模板
# 数据误删应急响应 SOP
## 触发条件
- 收到删除事件告警
- 用户报告文件丢失
- 监控显示目录文件数突降
## 响应步骤
1. 确认事故(10 分钟内)
- 联系报告人确认现象
- ssh 到目标主机初步确认
2. 立即止血(5 分钟内)
- 停 cron、停相关进程
- remount ro 或做 LVM 快照
3. 现场记录(15 分钟内)
- 抓 mount、lsof、ps、dmesg
4. 评估恢复方案(30 分钟内)
- 确认 FS 类型
- 选择恢复工具
5. 执行恢复(视情况)
- extundelete / debugfs / lsof
- 写入独立磁盘
6. 业务校验
- 文件大小、类型、内容
- 应用方确认
7. 复盘(事故后 24 小时内)
- 写复盘文档
- 落地行动项
关联页面
| 页面 | 关联点 |
|---|---|
| linux-mass-file-deletion-guide | |
| linux-disk-inspection-tools-guide | |
| linux-filesystem-directory-structure-guide | |
| linux-raid-lvm-basics-guide | |
| mysql-backup-selection-guide | |
| redis-backup-recovery |