lsof是最直接查进程打开文件的工具,但需sudo权限、注意+d/+d区别、识别(deleted)文件等关键点,否则易排查失败。

查进程打开的文件,lsof 是最直接有效的工具,但不加筛选时输出太杂、权限不对就漏关键项、误用参数反而卡住终端——这些问题比“怎么用”本身更常导致排查失败。
查指定 PID 进程打开了哪些文件
这是最常用也最容易出错的场景:你已经拿到 PID(比如 ps aux | grep nginx 看到 PID 是 1234),但执行 lsof -p 1234 却没结果或报 permission denied。
- 必须加
sudo:因为lsof要读取/proc/PID/fd/和内核内存,普通用户默认看不到其他用户的进程文件描述符 -
FD列里cwd表示当前工作目录,txt是可执行文件本身,DEL或(deleted)出现在NAME列末尾,说明文件已被rm删除但进程仍在写入——这是磁盘空间不释放的常见原因 - 如果只关心普通文件(排除 socket、pipe、inotify 等),可以加
-a -d ^cwd,^txt,^mem过滤掉非实际磁盘文件的条目
查某个文件或目录被谁占用了
当你想 umount /mnt/data 失败,或删不掉 /var/log/app.log,系统提示 “device busy” 或 “operation not permitted”,本质就是有进程正打开它。
- 查单个文件:直接
sudo lsof /var/log/app.log,输出里PID列就是持有句柄的进程号 - 查整个目录(含子目录):用
sudo lsof +D /var/log,注意这个操作会递归扫描,大目录下可能明显卡顿甚至超时;如只需一级目录,改用+d /var/log(小写 d) - 如果目标路径带空格或特殊字符,务必用引号包裹,否则 shell 会提前拆分,
lsof收到的是截断路径,查不到结果
查端口被哪个进程监听或连接
服务启动失败报 “address already in use”,或者想确认某端口(如 8080)是不是真被 java 进程占着,lsof -i 比 netstat 更可靠。
- 查监听端口:
sudo lsof -iTCP -sTCP:LISTEN,加上-P -n可禁用端口名和主机名解析,加快输出(sudo lsof -iTCP -sTCP:LISTEN -P -n) - 查特定端口:
sudo lsof -i :8080,支持 TCP/UDP 混合匹配;若只想看 TCP,写成sudo lsof -i tcp:8080 -
FD列显示12u这类数字,表示该 socket 对应的文件描述符编号;TYPE为IPv4或IPv6,NAME列末尾的(ESTABLISHED)、(LISTEN)等状态比netstat更准确
查已删除但仍被占用的大文件
磁盘 df 显示 100% 满,但 du -sh /* 2>/dev/null | sort -h 加起来才 60%,大概率是有大日志被 rm 了却还在被进程写入。
- 直接筛出已删除文件:
sudo lsof +L1,+L1 表示 link count 为 0 的文件(即已从目录树移除) - 输出中
NAME列末尾带(deleted)的行,结合SIZE/OFF列看实际占用字节数,比如1.2G就是它还在吃磁盘空间 - 恢复这类文件不需要第三方工具:找到对应
PID后,去/proc/PID/fd/下找那个指向(deleted)的 fd 链接,用cp /proc/PID/fd/N /tmp/recovered.log即可拷出内容(前提是进程没退出)
真正卡住排查的,往往不是不会用 lsof,而是忘了加 sudo、混淆了 +D 和 +d 的递归行为、或把 (deleted) 当成无关信息跳过——这些点在命令敲出去前多停半秒,就能省掉半小时翻日志。










