Linux lsof 命令深度解析:从文件描述符到进程追踪

摘要lsof(List Open Files)是 Linux 系统排查问题的利器。本文从核心原理(/proc 文件系统)出发,系统讲解端口占用排查、已删除文件空间找回、进程文件查看等高频场景,并涵盖组合查询、输出格式化等高级技巧与实战案例,帮你快速定位线上故障。

线上服务器突然报磁盘空间不足,df 一看还有 30%,但 du 统计出来却只有 10%。这种情况你遇到过吗?大概率是某个进程打开了已删除的文件,文件句柄没释放。

这时候 lsof 就派上用场了。

lsof 是什么

lsof 全称 List Open Files ,用于列出当前系统所有打开的文件。在 Linux 里,一切皆文件------普通文件、目录、网络套接字、管道、设备......这些都是文件。所以 lsof 能看到的不只是文件,还有网络连接、进程通信等。

核心原理:从 /proc 文件系统读取

lsof 的数据来源是 /proc 文件系统。每个进程在 /proc/<pid>/fd/ 目录下都有文件描述符的符号链接:

bash 复制代码
# 查看进程 1234 打开的文件描述符
ls -la /proc/1234/fd/

lrwx------ 1 root root 64 May 19 10:00 0 -> /dev/null
lrwx------ 1 root root 64 May 19 10:00 1 -> /dev/pts/0
lrwx------ 1 root root 64 May 19 10:00 2 -> /dev/pts/0
lrwx------ 1 root root 64 May 19 10:00 3 -> /var/log/app.log
lrwx------ 1 root root 64 May 19 10:00 4 -> socket:[12345]

lsof 本质上是遍历这些信息并格式化输出。理解这一点,遇到权限问题或特殊情况时就知道该怎么排查了。

常用场景与命令

1. 查看端口占用

bash 复制代码
# 查看谁在监听 8080 端口
lsof -i :8080

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx    1234 root   6u  IPv4  12345      0t0  TCP *:8080 (LISTEN)

# 只显示 TCP 连接
lsof -i TCP:8080

# 查看所有网络连接
lsof -i

输出字段解释:

  • FD : 文件描述符,u 表示读写模式
  • TYPE: 文件类型,IPv4/IPv6 表示网络套接字
  • NODE: 内核中的 inode 编号
  • NAME: 文件名或连接信息

2. 查看进程打开的文件

bash 复制代码
# 查看指定进程打开的所有文件
lsof -p 1234

# 查看多个进程
lsof -p 1234,5678,9012

# 只看普通文件(排除套接字、管道等)
lsof -p 1234 | grep REG

3. 找回已删除但仍占空间的文件

这是 lsof 最经典的用法。文件被删除后,如果有进程仍持有其句柄,磁盘空间不会释放:

bash 复制代码
# 找出已删除但仍被打开的文件
lsof | grep deleted

java      1234 root  1w  REG  8,1  1073741824  12345 /var/log/app.log (deleted)

# 恢复文件内容(通过 /proc)
cp /proc/1234/fd/1 /tmp/recovered.log

# 彻底释放空间:杀死进程或重启服务
kill -HUP 1234

4. 查看用户打开的文件

bash 复制代码
# 查看指定用户打开的文件
lsof -u nginx

# 排除某个用户
lsof -u ^root

# 查看多个用户
lsof -u nginx,mysql

5. 查看目录被谁占用

bash 复制代码
# 查看谁在使用 /var/log 目录
lsof +D /var/log

# 递归查看(+D 会递归,+d 不会)
lsof +d /var/log

6. 查看文件被谁打开

bash 复制代码
# 查看指定文件被哪个进程打开
lsof /var/log/app.log

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
tail     5678 root   3r   REG  8,1     1024  12345 /var/log/app.log

高级技巧

组合条件查询

bash 复制代码
# 查看 nginx 进程的网络连接
lsof -c nginx -i

# 查看指定用户的 TCP 连接
lsof -u nginx -i TCP

# 查看指定进程的网络连接
lsof -p 1234 -i

# 使用 AND 逻辑(同时满足)
lsof -a -c nginx -i TCP

# 使用 OR 逻辑(默认)
lsof -c nginx -c mysql

输出格式化

bash 复制代码
# 只输出 PID
lsof -t -i :8080

# 配合 kill 使用
kill -9 $(lsof -t -i :8080)

# 输出为 CSV 格式(便于脚本处理)
lsof -F pcn | awk '/^p/{pid=substr($0,2)} /^c/{cmd=substr($0,2)} /^n/{print pid","cmd","substr($0,2)}'

查看块设备

bash 复制代码
# 查看谁在使用 /dev/sda1
lsof /dev/sda1

# 查看所有块设备
lsof +c 0 | grep -E "^COMMAND|/dev/sd"

性能考量

lsof 需要遍历所有进程的 /proc/<pid>/fd/ 目录,在进程数很多的系统上会比较慢。几个优化建议:

  1. 缩小查询范围:指定进程、用户或端口,避免全量扫描
  2. 使用 -n 参数:不解析主机名,加快输出速度
  3. 使用 -P 参数:不解析端口名,直接显示数字
bash 复制代码
# 快速查询,不解析名称
lsof -n -P -i :8080

与其他工具对比

工具 主要用途 优势
lsof 列出打开的文件 全面,支持网络、文件、设备
fuser 查看谁在使用文件/套接字 轻量,适合脚本
ss 查看套接字统计 快速,取代 netstat
netstat 查看网络连接 传统工具,逐渐被 ss 取代
bash 复制代码
# fuser 查看 8080 端口占用
fuser 8080/tcp

# ss 查看 8080 端口
ss -tlnp | grep 8080

实战案例

案例 1:排查 "Too many open files"

bash 复制代码
# 查看系统打开文件限制
ulimit -n

# 查看指定进程打开的文件数量
lsof -p 1234 | wc -l

# 查看所有进程打开文件数排序
lsof | awk '{print $1}' | sort | uniq -c | sort -nr | head

案例 2:排查磁盘空间消失

bash 复制代码
# 现象:df 显示空间不足,但 du 统计正常
df -h
du -sh /*

# 用 lsof 找出罪魁祸首
lsof | grep deleted | sort -k7 -nr | head

# 解决:重启对应服务或杀死进程

案例 3:排查服务启动失败(端口被占用)

bash 复制代码
# 启动服务报 "Address already in use"
lsof -i :8080

# 强制杀掉占用端口的进程
kill -9 $(lsof -t -i :8080)

总结

lsof 是排查线上问题的利器,熟练掌握能帮你快速定位:

  • 端口占用问题
  • 磁盘空间消失问题
  • 文件锁定问题
  • 网络连接追踪

记住几个核心参数:-i 查网络、-p 查进程、-u 查用户、+D 查目录。遇到问题时,先想到 /proc 文件系统,再配合 lsof 工具,基本都能找到答案。


相关工具

相关推荐
A小辣椒14 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒18 小时前
TShark:基础知识
linux
BingoGo18 小时前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack18 小时前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
AlfredZhao20 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户3074596982072 天前
PHP 扩展——从入门到理解
php
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
鹏仔先生2 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php