暗色模式

lsof 进程文件排查:从打开文件到端口占用的完整指南

技术教程
2026-08-14
6
0
本文要点
  • lsof 可以列出任何进程打开的文件,从普通文件、目录到共享库、网络连接全覆盖
  • 输出列含义:COMMAND/PID/USER 定位进程,FD/TYPE 说明文件描述符与类型,NAME 是实际路径或连接信息
  • 按端口找进程:lsof -i :3000 一条命令即可定位是谁占用了端口
  • lsof +L1 能找出"已删除但磁盘空间未释放"的文件,是磁盘清理的救命工具
  • 常用过滤参数:-u 按用户、-p 按 PID、-c 按命令名、-i 按网络

lsof 能做什么

在 Linux 上,一切皆文件:普通文件、目录、设备、socket、管道,甚至进程间通信用的匿名 inode,最终都以"文件描述符"的形式被进程持有。而 lsof(List Open Files)就是把这些打开的文件全部列出来的工具——它通过读取 /proc/<pid>/fd/proc/<pid>/maps 等内核接口,把每个进程持有的文件描述符整理成一张清单。

它的典型使用场景包括:

  • 端口占用排查:服务起不来提示"端口被占用",一条 lsof -i :8080 找出元凶;
  • 磁盘空间未释放rm 删除大文件后 df 仍显示满,用 lsof +L1 找出还在占用文件句柄的进程;
  • 确认进程工作目录与运行文件:判断一个进程到底是从哪个路径启动的、日志写到哪里;
  • 安全审计:查看某个用户或某个进程打开过哪些文件。

Ubuntu 上一般已预装,未安装时用 apt install lsof 即可。

输出列的含义

先看一张基础输出图,命令是 lsof -u www-data,只显示 www-data 用户打开的 12 行:

lsof 基础输出与列含义

每一列的含义如下:

列名含义
COMMAND进程的命令名
PID进程 ID
USER进程所属用户
FD文件描述符,如 cwd(当前工作目录)、rtd(根目录)、txt(程序代码)、mem(内存映射文件)、数字+模式(如 24u 表示 24 号描述符、u 读写、r 只读、w 只写)
TYPE文件类型,DIR 目录、REG 普通文件、IPv4/IPv6 网络连接、CHR 字符设备等
DEVICE设备号(主:次)
SIZE/OFF文件大小或读写偏移量
NODE文件的 inode 号,网络连接则显示协议信息
NAME文件路径或连接端点

对照上图就能串起来:node 进程(PID 14934,用户 www-data)的 cwd 指向 /opt/myapprtd 指向 /txt 指向可执行文件 /usr/bin/node,后续多行 mem 则是它加载的共享库(libstdc++、libicu、libcrypto 等)。一个运行中的 Node 服务会打开哪些文件、日志写在哪,一眼可见。

按用户、进程和命令过滤

服务器上进程很多,直接跑 lsof 会输出几千行。掌握过滤参数是关键。

按用户过滤:-u

lsof -u www-data 只显示 www-data 用户的进程,上面图一就是这个命令。排除某个用户用 ^ 前缀:lsof -u ^root

按 PID 过滤:-p

知道 PID 后查它打开了哪些文件:

lsof -p 14934

结合 pgrep 还能按名字拿 PID 再查:lsof -p $(pgrep -x nginx)

按命令名过滤:-c

lsof -c sshd

-c 匹配进程名(正则),会列出所有名字含 sshd 的进程打开的文件,比先查 PID 再传 -p 更省事。

按端口和网络连接排查

这是 lsof 用得最多的场景。服务启动报 address already in use,马上定位:

lsof -i :3000

按端口定位占用进程

输出很直观:node 进程(PID 14934,用户 www-data)的 24 号描述符,类型是 IPv6 socket,TCP *:3000 (LISTEN) 表示它正监听所有网卡的 3000 端口。加 -n -P 可以跳过 DNS 反解和端口名转换,让 IP 和端口都以数字形式输出,排查时更快、结果更可读。

几个常用的网络排查变体:

# 查看所有监听中的 TCP 端口(含 PID,配合 kill 用)
lsof -iTCP -sTCP:LISTEN -n -P

# 查看所有已建立的连接
lsof -iTCP -sTCP:ESTABLISHED

# 只看 22 号端口
lsof -i :22

# 按网段过滤(含 UDP)
lsof -i@192.168.1.0/24

注意:普通用户只能看到自己进程的网络连接,看全系统需要 root 权限。

已删除但未释放的文件

运维里最经典的"幽灵"问题:明明删了日志,df -h 磁盘还是满的。原因是一个进程还开着该文件的句柄,文件虽然从目录里删了,但 inode 和磁盘块仍被占用。lsof +L1 专门列出这类文件(+L1 表示列出 link count 小于 1,即无硬链接、已不可见的文件):

lsof +L1

已删除但未释放的文件

图中最后一行正是我们人为制造的场景:一个 sleep 进程用文件描述符 9w(9 号、只写)打开了 /root/lsof-demo/big.log,文件被 rm 删除后 NAME 末尾多了 (deleted) 标记。此时 duls 都看不到它,但磁盘空间依然被占着。

定位到持有句柄的 PID 后,处理方式看业务而定:可以杀掉进程释放句柄(kill <PID>),或者像 Nginx 日志那样通过信号重开日志文件。/proc 里也能看到这个链接:ls -l /proc/<PID>/fd/9 会显示 /root/lsof-demo/big.log (deleted)

常用场景速查

目标命令
看某个用户打开的文件lsof -u www-data
看某个 PID 打开的文件lsof -p 1234
看某个命令打开的文件lsof -c nginx
谁占用了 8080 端口lsof -i :8080
所有监听 TCP 端口lsof -iTCP -sTCP:LISTEN -n -P
谁连着某台服务器lsof -i@10.0.0.5
已删除未释放的文件lsof +L1
列出某目录下被打开的文件lsof +D /var/log

小结

lsof 把内核 /proc 里的文件描述符信息整理成了直观的清单,是进程、文件、网络三者的交叉检索工具。端口占用用它找 PID,磁盘不释放用它找句柄,排查"谁打开了这个文件"用它看进程。配合 -u-p-c-i 几个过滤参数,几百上千行输出也能快速收敛到目标进程。

参考资料

发表评论

暂无评论,快来抢沙发吧!