深入理解 lsof:麒麟Linux 系统中查看打开文件的利器
#Linux #麒麟 #lsof
在 Linux 系统中,"一切皆文件" 是核心设计理念之一。从普通文本到网络套接字,从设备驱动到管道,所有资源都以文件形式呈现。
管理这些 "文件" 对于系统运维、故障排查至关重要,而 lsof(List Open Files)就是一款专门用于列出系统中所有被进程打开的文件的强大工具。
本文将深入解析 lsof 的工作原理、常用功能及实战场景,帮助你掌握这一运维必备技能。
一、lsof 是什么?
lsof 是 "List Open Files" 的缩写,它能够列出系统中所有被进程打开的文件信息。这里的 "文件" 涵盖了以下类型:
- 普通文件(文本、二进制文件等)
- 目录
- 设备文件(块设备、字符设备)
- 网络文件(TCP 连接、UDP 套接字、网络端口等)
- 管道(命名管道、无名管道)
- 符号链接
lsof 通过解析 /proc 文件系统(进程信息伪文件系统)获取进程打开的文件描述符信息,进而展示进程与文件的关联关系。
它几乎是排查 "文件占用"" 端口冲突 ""资源泄漏" 等问题的首选工具。
二、lsof 的工作原理
Linux 系统中,每个进程在启动后会在 /proc/<PID>/fd 目录下创建文件描述符(File Descriptor),记录该进程打开的所有文件。例如,/proc/1234/fd/0 表示 PID 为 1234 的进程打开的标准输入(stdin)。
lsof 的工作流程如下:
- 遍历系统中所有活跃进程(/proc 目录下的进程 ID 目录);
- 读取每个进程的文件描述符信息(/proc/<PID>/fd);
- 解析文件描述符对应的实际文件路径、类型、状态等;
- 汇总并格式化输出结果,展示进程与文件的关联关系。
由于需要访问系统核心进程信息,lsof 通常需要 root 权限才能查看所有进程的完整信息(普通用户仅能查看自己的进程)。
三、核心功能与常用命令
lsof 的命令格式为:lsof [选项],默认情况下会输出所有进程打开的所有文件(内容较多),实际使用中需结合选项筛选。以下是最常用的功能及示例:
1. 查看特定进程打开的文件
选项:-p <PID>(指定进程 ID)
用途:分析某个进程正在读写的文件(如日志、配置文件、数据库文件等)。
#查看pg数据库的进程
pidof postgres
1848 1847 1846 1844 1843 1842# 查看 PID 为 1842的进程打开的所有文件
lsof -p 1842
输出结果
[root@db1 ~]# lsof -p 1848
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
postgres 1848 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1848 postgres rtd DIR 253,0 4096 128 /
postgres 1848 postgres txt REG 253,0 55109064 19922937 /usr/local/postgres/bin/postgres
postgres 1848 postgres mem REG 0,20 1048576 56387 /dev/shm/PostgreSQL.4284816928
postgres 1848 postgres mem REG 253,0 55496 50481071 /usr/lib64/libnss_files-2.28.so
postgres 1848 postgres DEL REG 0,5 56373 /dev/zero
2. 查看特定文件被哪些进程占用
用法:直接指定文件名或路径
用途:解决 "文件无法删除"" 设备忙 "等问题(如删除日志文件时提示"Device or resource busy")。
# 查看 /var/log/messages 被哪些进程打开
lsof /var/log/messages# 查看 /etc/passwd 被哪些进程访问
lsof /etc/passwd
若文件已被删除但仍被进程占用(常见于日志轮转场景),NAME 列会显示 (deleted) 标记,此时需重启相关进程释放资源。
3. 分析网络连接与端口占用
选项:-i(网络相关文件)
用途:排查端口冲突、异常连接、网络服务状态等问题,是网络排障的核心工具。
(一)列出所有网络连接(TCP/UDP)
[root@db1 data]# lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 46u IPv6 27292 0t0 TCP *:websm (LISTEN)
rpcbind 873 rpc 6u IPv4 26744 0t0 UDP *:sunrpc
rpcbind 873 rpc 7u IPv4 26745 0t0 TCP *:sunrpc (LISTEN)
rpcbind 873 rpc 8u IPv6 26746 0t0 UDP *:sunrpc
rpcbind 873 rpc 9u IPv6 26747 0t0 TCP *:sunrpc (LISTEN)
chronyd 923 chrony 6u IPv4 27988 0t0 UDP localhost:323
chronyd 923 chrony 7u IPv6 27989 0t0 UDP localhost:323
sshd 1382 root 5u IPv4 47971 0t0 TCP *:ssh (LISTEN)
sshd 1382 root 6u IPv6 47973 0t0 TCP *:ssh (LISTEN)
sshd 1647 root 5u IPv4 50044 0t0 TCP db1:ssh->192.168.74.1:59521 (ESTABLISHED)
sshd 1659 root 5u IPv4 50044 0t0 TCP db1:ssh->192.168.74.1:59521 (ESTABLISHED)
postgres 1842 postgres 6u IPv6 56382 0t0 TCP localhost:postgres (LISTEN)
postgres 1842 postgres 7u IPv4 56383 0t0 TCP localhost:postgres (LISTEN)
(二)仅查看 TCP 连接(包括监听、已建立等状态)
[root@db1 data]# lsof -i tcp
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 46u IPv6 27292 0t0 TCP *:websm (LISTEN)
rpcbind 873 rpc 7u IPv4 26745 0t0 TCP *:sunrpc (LISTEN)
rpcbind 873 rpc 9u IPv6 26747 0t0 TCP *:sunrpc (LISTEN)
sshd 1382 root 5u IPv4 47971 0t0 TCP *:ssh (LISTEN)
sshd 1382 root 6u IPv6 47973 0t0 TCP *:ssh (LISTEN)
sshd 1647 root 5u IPv4 50044 0t0 TCP db1:ssh->192.168.74.1:59521 (ESTABLISHED)
sshd 1659 root 5u IPv4 50044 0t0 TCP db1:ssh->192.168.74.1:59521 (ESTABLISHED)
postgres 1842 postgres 6u IPv6 56382 0t0 TCP localhost:postgres (LISTEN)
postgres 1842 postgres 7u IPv4 56383 0t0 TCP localhost:postgres (LISTEN)
sshd 2641 root 5u IPv4 64609 0t0 TCP db1:ssh->192.168.74.1:63744 (ESTABLISHED)
sshd 2644 root 5u IPv4 64609 0t0 TCP db1:ssh->192.168.74.1:63744 (ESTABLISHED)
(三) 查看PG数据库5432端口被哪些进程占用(常用于解决"端口已被使用"错误)
[root@db1 data]# lsof -i :5432
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
postgres 1842 postgres 6u IPv6 56382 0t0 TCP localhost:postgres (LISTEN)
postgres 1842 postgres 7u IPv4 56383 0t0 TCP localhost:postgres (LISTEN)
(四)查看 22 端口的 TCP 连接(如 SSH 连接)
[root@db1 data]# lsof -i tcp:22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1382 root 5u IPv4 47971 0t0 TCP *:ssh (LISTEN)
sshd 1382 root 6u IPv6 47973 0t0 TCP *:ssh (LISTEN)
(五)查看与 192.168.1.100 的网络连接
[root@db1 data]# lsof -i @192.168.74.46
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1647 root 5u IPv4 50044 0t0 TCP db1:ssh->192.168.74.1:59521 (ESTABLISHED)
sshd 1659 root 5u IPv4 50044 0t0 TCP db1:ssh->192.168.74.1:59521 (ESTABLISHED)
sshd 2641 root 5u IPv4 64609 0t0 TCP db1:ssh->192.168.74.1:63744 (ESTABLISHED)
sshd 2644 root 5u IPv4 64609 0t0 TCP db1:ssh->192.168.74.1:63744 (ESTABLISHED)
4. 查看特定用户打开的文件
选项:-u <用户名>
用途:监控用户活动,排查特定用户的进程资源占用。
查看用户 postgres 打开的部分文件
[root@db1 data]# lsof -u postgres | head -n 10
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
postgres 1842 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1842 postgres rtd DIR 253,0 4096 128 /
postgres 1842 postgres txt REG 253,0 55109064 19922937 /usr/local/postgres/bin/postgres
postgres 1842 postgres mem REG 253,0 55496 50481071 /usr/lib64/libnss_files-2.28.so
postgres 1842 postgres DEL REG 0,5 56373 /dev/zero
postgres 1842 postgres mem REG 253,0 215159920 3654424 /usr/lib/locale/locale-archive
postgres 1842 postgres mem REG 253,0 149736 50539780 /usr/lib64/libgpg-error.so.0.29.0
postgres 1842 postgres mem REG 253,0 604616 50509362 /usr/lib64/libpcre2-8.so.0.10.0
postgres 1842 postgres mem REG 253,0 14336 50480550 /usr/lib64/libsecurity.so.0.0.0
5. 递归查看目录下的文件占用
选项:+D <目录路径>
用途:分析某个目录(如网站根目录、数据目录)下所有文件的占用情况。
递归查看 /data/pgdata/data/ 目录下被打开的文件(包括子目录)
[root@db1 data]# lsof +D /data/pgdata/data/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
postgres 1842 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1843 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1844 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1846 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1847 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1847 postgres 6u REG 253,0 8192 964768 /data/pgdata/data/global/1262
postgres 1848 postgres cwd DIR 253,0 4096 20104278 /data/pgdata/data
postgres 1848 postgres 6u REG 253,0 0 964778 /data/pgdata/data/global/6100
bash 2123 root cwd DIR 253,0 4096 20104278 /data/pgdata/data
lsof 2784 root cwd DIR 253,0 4096 20104278 /data/pgdata/data
lsof 2785 root cwd DIR 253,0 4096 20104278 /data/pgdata/data
与 -d 选项结合可进一步筛选文件类型(如 lsof +D /var/log -d txt 查看日志目录下的文本文件)。
6. 高级筛选:组合参数
lsof 支持多参数组合,通过 -a(逻辑与)实现精准筛选:
# 查看 root 用户的 TCP 连接(-u root 与 -i tcp 的交集)
lsof -u root -a -i tcp# 查看 nginx 进程占用的 443 端口(-c 匹配进程名前缀)
lsof -c nginx -a -i :443# 仅输出进程 ID(配合 kill 命令快速终止进程)
lsof -t -i :8080 | xargs kill -9
四、实战场景:解决实际问题
场景 1:端口被占用,无法启动服务
当启动服务时提示 "Address already in use",可用 lsof 快速定位占用端口的进程:
# 查找 8080 端口的占用进程
lsof -i :8080# 输出示例:
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
# java 1234 app 42u IPv6 12345 0t0 TCP *:8080 (LISTEN)# 终止占用进程(根据 PID)
kill -9 1234
场景 2:删除文件后磁盘空间未释放
Linux 中,若文件被进程占用,删除后空间不会立即释放(需进程关闭文件)。用 lsof 可找到占用已删除文件的进程:
# 查找所有已删除但仍被占用的文件
lsof | grep deleted# 输出示例:
# rsyslogd 567 root 3w REG 8,1 1048576 1234 /var/log/old.log (deleted)# 重启进程释放空间(或发送 SIGHUP 信号让进程重新打开文件)
systemctl restart rsyslog
场景 3:排查异常网络连接
发现服务器有异常外部连接时,用 lsof 分析连接来源和关联进程:
# 查看所有已建立的外部连接
lsof -i | grep ESTABLISHED# 定位连接到可疑 IP(如 203.0.113.5)的进程
lsof -i @203.0.113.5
场景四:排查挂载点占用
当卸载挂载点时提示 "target is busy",可用 lsof 快速定位占用挂载点的进程:
# 尝试卸载/dbsoft挂载点
umount /dbsoft
umount: /dbsoft: target is busy.#查看占用/dbsoft的进程
lsof /dbsoft/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 2409 postgres cwd DIR 259,4 65 128 /dbsoft# 终止占用进程(根据 PID)
kill -9 2409 #卸载成功
umount /dbsoft
五、注意事项
- 权限问题:普通用户只能查看自己的进程,查看系统级进程需用 sudo 或 root 权限。
- 性能影响:lsof 遍历所有进程和文件描述符,在高负载系统(如进程数 > 10000)中可能耗时较长,建议避免频繁执行。
- 输出解读:重点关注 COMMAND(进程名)、PID(进程 ID)、FD(文件描述符)、TYPE(文件类型)、NAME(文件路径 / 网络信息)。
六、总结
lsof 是 Linux 系统中功能强大的 "文件侦探",它不仅能列出进程与文件的关联,更能深入分析网络连接、资源占用等核心系统状态。掌握 lsof 的常用命令和实战技巧,能显著提升系统排障效率,解决端口冲突、文件占用、资源泄漏等常见问题。
🚀 更多数据库干货,欢迎关注【安呀智数据坊】
如果你觉得这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐ 和留言 💬 交流,让我知道你还想了解哪些数据库知识!
📬 想系统学习更多数据库实战案例与技术指南?
📊 实战项目分享
📚 技术原理讲解
🧠 数据库架构思维
🛠 工具推荐与实用技巧
立即关注,get知识抢先一步,持续更新中 👇