lsof 默认查不到已删除但仍在使用的文件,需用 lsof +l1 或遍历 /proc/[0-9]*/fd/ 查 deleted 链接;恢复时应先暂停进程、确认 fd 可读,再用 dd 复制;进程退出后仅能依赖 extundelete 或 debugfs,且须立即卸载分区防止覆盖。

lsof 查不到已删除但仍在使用的文件?检查 /proc/*/fd
当文件被 rm 删除,但仍有进程打开它时,lsof 默认不会显示“已删除”状态的条目——它只列出当前路径存在且可 stat 的文件。真正线索藏在 /proc 文件系统里:/proc/[pid]/fd/ 下的符号链接会指向 deleted 标记的路径。
实操建议:
- 用
lsof +L1强制列出所有链接计数为 0 的文件(即已被删但句柄仍开),这是最直接的方式 - 若
+L1无输出,说明进程没用常规方式打开(比如 mmap 或子进程继承),此时应遍历/proc/[0-9]*/fd/:for p in /proc/[0-9]*; do ls -l "$p/fd/" 2>/dev/null | grep deleted; done | head -20
- 注意:需 root 权限才能读取其他用户进程的
/proc/[pid]/fd/,普通用户只能看到自己的
恢复文件时 cp /proc/[pid]/fd/[fd_num] 直接失败?确认 fd 是否可读且未截断
从 /proc/[pid]/fd/[n] 复制文件看似简单,但常见失败原因不是权限,而是文件描述符本身的状态:比如进程以 O_WRONLY 打开、或已 seek 到末尾、或底层存储已被覆盖(ext4 的延迟分配可能让块被重用)。
实操建议:
- 先检查 fd 状态:
ls -l /proc/[pid]/fd/[n],确认链接目标含deleted字样且权限含r - 用
file /proc/[pid]/fd/[n]看是否能识别类型;若返回cannot open,说明该 fd 已不可读(如写模式打开、或进程已退出) - 复制时加
dd更稳妥,避免缓冲问题:dd if=/proc/[pid]/fd/[n] of=recovered.log bs=8k
- 不要用
cat管道重定向——某些日志类程序会因 SIGPIPE 中断写入,导致恢复不全
恢复后文件大小为 0 或不完整?检查进程是否还在追加写入
即使成功复制了 fd 内容,如果原进程仍在向该文件写入(比如日志服务),你复制的只是某一时刻的快照。更糟的是,若进程使用 truncate() 或 lseek(SEEK_END) 后写入,/proc/[pid]/fd/[n] 可能反映的是逻辑偏移而非物理长度。
PyCharm 2026.2.0.1 Linux版提供 JetBrains 官方 2026.2.0.1 版本安装包,适合需要指定 PyCharm 版本进行 Python 项目开发、运行和调试的用户。
实操建议:
- 恢复前优先暂停进程:
kill -STOP [pid](别用 TERM/KILL,会关闭 fd) - 用
lsof -p [pid]确认 fd 对应的原始路径和文件大小(SIZE/OFF列是当前 offset,非总长) - 若文件是日志,检查其 inode 是否被轮转工具(如 logrotate)通过
copytruncate修改过——这种情况下,恢复的其实是旧内容,新写入已到新文件 - 恢复后立即
stat源 fd 和目标文件,比对Size和Blocks,差异大说明有稀疏或截断
ext4 上恢复失败还剩什么招?别忽略 extundelete 和 debugfs 的边界能力
lsof + /proc/fd 是首选,但它依赖进程存活。一旦进程退出,fd 关闭,内核释放 inode 链接,就只能靠文件系统层恢复——而 ext4 默认不保留删除痕迹,extundelete 效果有限,尤其启用了 extents 或 journal=ordered。
实操建议:
- 立刻卸载分区:
umount /dev/sdXN,防止新写入覆盖数据块(若无法卸载,至少停掉所有写入该分区的服务) -
extundelete仅对未覆写的 block 有效,且不支持 ext4 的 extent 特性(报extents not supported就放弃) - 万不得已时用
debugfs手动查 inode:debugfs /dev/sdXN -R "lsdel"
,看是否有未清除的目录项;再用icat提取,但需知道原始 inode 号 - 记住:SSD 上 TRIM 后基本无解,机械盘也得趁早操作——延迟一小时,恢复成功率断崖下降
最易被忽略的一点:很多脚本或服务会把日志 fd 传给子进程(如 bash -c 'exec 3>/var/log/app.log'),父进程删了文件,子进程仍持有 fd。这时 lsof +L1 可能找不到父进程,但子进程的 /proc/[pid]/fd/ 里藏着关键链接——得顺着 PPid 和 lsof -p [pid] 往上捋两层。










