当前位置:首页>Linux>Linux 运维神器 lsof!搞定端口占用 / 磁盘不释放等问题

Linux 运维神器 lsof!搞定端口占用 / 磁盘不释放等问题

  • 2026-09-02 20:26:11
Linux 运维神器 lsof!搞定端口占用 / 磁盘不释放等问题

字数 5289,阅读大约需 27 分钟

在Rocky Linux运维工作中,你是否遇到过这样的困惑:端口被占用却找不到占用进程?文件删除后磁盘空间仍未释放?程序崩溃提示“文件已打开”却不知道哪个进程在占用?其实,解决这些问题的“万能钥匙”,就是系统自带的命令——lsof。

lsof的全称是“list open files”,直译就是“列出所有打开的文件”。在Linux系统中,“一切皆文件”,无论是普通文件、目录、设备,还是网络套接字、管道,只要被进程打开,lsof都能将其“打回原形”。它就像一个系统侦探,能帮你摸清每一个进程与文件的关联,轻松排查各类运维难题。

本文将以Rocky Linux(与CentOS、RHEL完全兼容)为环境,从入门到精通,用最浅显的语言、最实用的示例,手把手教你掌握lsof,让它成为你运维工具箱中的“得力干将”。

第一部分:入门基础——认识lsof,迈出第一步

1.1 什么是lsof?为什么要用它?

如前文所说,lsof的核心功能是列出系统中所有被进程打开的文件。在Linux中,任何进程运行时,都会打开一些文件(哪怕是隐性的),比如:

  • • 程序本身(如/bin/ls)会被打开为“可执行文件”;
  • • 进程运行时读取的配置文件(如/etc/profile);
  • • 网络连接(如TCP/UDP端口,本质是“网络文件”);
  • • 设备文件(如磁盘、键盘、打印机,对应/dev目录下的文件);
  • • 管道、套接字等进程间通信的“虚拟文件”。

当你遇到以下场景时,lsof就能派上大用场:

  • • 场景1:启动服务提示“端口已被占用”(如Nginx启动失败,提示80端口被占用);
  • • 场景2:删除大文件后,df命令查看磁盘空间仍未释放(大概率是文件被进程占用,删除后仅删除了目录项,进程仍在读取文件内容);
  • • 场景3:排查恶意进程(如挖矿进程,通过lsof查看其打开的文件、网络连接,判断其行为);
  • • 场景4:查看某个进程正在读取/写入哪些文件(如排查MySQL进程正在操作的日志、数据文件)。

1.2 安装lsof(Rocky Linux默认已安装)

Rocky Linux 8/9系统默认已预装lsof,若未安装(极少情况),执行以下命令安装:

# 安装lsof(root权限)
dnf install -y lsof

# 验证安装是否成功

lsof -v  # 查看lsof版本,出现版本信息即为安装成功

注意:lsof需要root权限才能查看所有进程的打开文件,普通用户只能查看自己启动的进程对应的文件。因此,后续示例均建议以root用户执行(或加sudo)。

1.3 最基础的用法:直接输入lsof

直接在终端输入lsof,会列出系统中所有进程打开的所有文件,输出内容非常多(几千行甚至上万行),我们先看一下输出的核心字段含义(重点记,后续所有示例都会用到):

# 直接执行lsof(输出示例,仅截取前几行)
lsof
COMMAND    PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
systemd      1  root  cwd    DIR    8,1     4096       2 /
systemd      1  root  rtd    DIR    8,1     4096       2 /
systemd      1  root  txt    REG    8,1  1627008 1310721 /usr/lib/systemd/systemd
systemd      1  root  mem    REG    8,1   200728 1311045 /usr/lib64/libuuid.so.1.3.0
sshd        986  root  txt    REG    8,1   823488 1311447 /usr/sbin/sshd
sshd        986  root    3u  IPv4  19880      0t0     TCP *:ssh (LISTEN)

核心字段详解(必记):

字段
含义
示例说明
COMMAND
打开文件的进程名称
systemd、sshd、nginx
PID
进程的ID(唯一标识)
1(systemd是系统初始化进程,PID永远是1)、986(sshd进程)
USER
进程的所属用户
root(系统进程)、nginx(Nginx进程)
FD
文件描述符(标识进程打开的文件)
cwd(当前工作目录)、txt(可执行文件)、mem(内存映射文件)、3u(u表示可读可写)
TYPE
文件类型
DIR(目录)、REG(普通文件)、TCP(TCP网络连接)、UDP(UDP网络连接)
DEVICE
设备编号(对应/dev下的设备)
8,1(表示/dev/sda1,8是主设备号,1是次设备号)
SIZE/OFF
文件大小(普通文件)或偏移量(网络文件/管道)
1627008(单位字节)、0t0(网络连接无固定大小,偏移量为0)
NODE
文件的inode编号(Linux中文件的唯一标识)
2(根目录/的inode编号)
NAME
文件的路径或网络连接信息
/(根目录)、*:ssh(监听所有IP的ssh端口,即22端口)
提示:FD字段中常见的标识含义:
  • • cwd:current working directory,进程的当前工作目录;
  • • txt:text,进程的可执行文件(程序本身);
  • • mem:memory-mapped file,内存映射文件(如共享库);
  • • 0:标准输入(stdin),通常对应键盘;
  • • 1:标准输出(stdout),通常对应终端;
  • • 2:标准错误(stderr),通常对应终端;
  • • u:表示文件可读写(read/write);
  • • r:表示文件只读(read);
  • • w:表示文件只写(write)。

第二部分:核心参数——掌握这些,够用80%场景

直接执行lsof输出太多,实际使用中,我们都会搭配参数过滤需要的信息。lsof的参数非常多,但常用的只有十几个,下面逐个讲解,每个参数都搭配Rocky Linux下的实际示例,确保你能直接复制使用。

2.1 按进程过滤:-p、-c、-u

场景:查看某个进程打开的文件、某个用户的所有进程打开的文件、某个名称的进程打开的文件。

2.1.1 -p:按PID过滤(最常用)

语法:lsof -p 进程ID(可多个,用逗号分隔)

示例1:查看PID为1的systemd进程打开的所有文件(系统初始化进程,打开的文件最多)

lsof -p 1

示例2:查看PID为986(sshd)和1000(nginx)两个进程打开的文件

lsof -p 986,1000

示例3:排除某个PID(加^),查看除了PID为1之外的所有进程打开的文件

lsof -p ^1

2.1.2 -c:按进程名称过滤(模糊匹配)

语法:lsof -c 进程名称(只需要前缀,模糊匹配)

示例1:查看所有名称以“sshd”开头的进程打开的文件(即sshd进程)

lsof -c sshd

示例2:查看所有名称以“ng”开头的进程打开的文件(可能匹配nginx、ngrep等)

lsof -c ng

示例3:排除某个进程名称(加^),查看除了nginx进程之外的所有进程打开的文件

lsof -c ^nginx

2.1.3 -u:按用户过滤(查看某个用户的所有进程打开的文件)

语法:lsof -u 用户名/用户ID

示例1:查看nginx用户的所有进程打开的文件(排查Nginx进程的文件操作)

lsof -u nginx

示例2:查看用户ID为1000的用户(普通用户)的进程打开的文件

lsof -u 1000

示例3:排除某个用户(加^),查看除了root用户之外的所有进程打开的文件

lsof -u ^root

2.2 按文件/目录过滤:+d、+D、直接跟文件名

场景:查看某个文件被哪个进程打开、某个目录下的文件被哪些进程打开(排查文件占用、删除后空间不释放)。

2.2.1 直接跟文件名:查看某个文件被哪个进程打开(最常用)

语法:lsof 文件名(绝对路径或相对路径)

示例1:查看/etc/passwd文件被哪个进程打开(该文件是用户配置文件,通常有多个进程读取)

lsof /etc/passwd

示例2:排查“删除文件后磁盘空间不释放”问题(假设删除了/var/log/nginx/access.log)

# 查看被删除的文件是否仍被进程占用(文件名后会显示(deleted))
lsof /var/log/nginx/access.log

# 若输出结果中NAME字段显示 /var/log/nginx/access.log (deleted),说明该文件被进程占用

# 此时只需杀死对应的PID,即可释放磁盘空间:kill -9 PID

2.2.2 +d:查看某个目录下的文件被哪些进程打开(不递归子目录)

语法:lsof +d 目录路径

示例:查看/var/log目录下的文件被哪些进程打开(不包含子目录,如/var/log/nginx)

lsof +d /var/log

2.2.3 +D:查看某个目录及其子目录下的文件被哪些进程打开(递归,慎用大目录)

语法:lsof +D 目录路径

示例:查看/var/log目录及其所有子目录下的文件被哪些进程打开(包含/var/log/nginx、/var/log/messages等)

lsof +D /var/log

警告:不要对根目录(/)或大目录(如/home)使用+lsof +D,会遍历所有子目录,输出极多,且消耗系统资源。

2.3 按网络连接过滤:-i(最核心、最常用)

场景:查看端口被哪个进程占用、查看某个进程的网络连接、查看TCP/UDP连接状态(排查端口占用、网络异常)。这是lsof最常用的场景之一,务必熟练掌握。

语法:lsof -i [参数],参数可组合(协议、端口、IP、状态)

2.3.1 基础用法:查看所有网络连接(TCP+UDP)

lsof -i

输出中TYPE字段为TCP或UDP,NAME字段显示网络连接信息(如*:ssh表示监听所有IP的22端口,192.168.1.100:ssh->192.168.1.200:54321表示TCP连接)。

2.3.2 按端口过滤(最常用:排查端口占用)

语法:lsof -i :端口号(可多个端口,用逗号分隔;可指定端口范围)

示例1:查看80端口被哪个进程占用(Nginx默认端口,启动失败时常用)

lsof -i :80

示例2:查看80、443、22三个端口被哪些进程占用(常用Web+SSH端口)

lsof -i :80,443,22

示例3:查看1000-2000端口范围内的所有连接

lsof -i :1000-2000

2.3.3 按协议过滤(TCP/UDP)

语法:lsof -i TCP 或 lsof -i UDP

示例1:查看所有TCP连接(如Web服务、SSH连接)

lsof -i TCP

示例2:查看所有UDP连接(如DNS解析、NTP时间同步)

lsof -i UDP

2.3.4 按IP过滤(查看某个IP的网络连接)

语法:lsof -i @IP地址(本地IP或远程IP)

示例1:查看本地IP为192.168.1.100的所有网络连接

lsof -i @192.168.1.100

示例2:查看远程IP为192.168.1.200的所有网络连接(即本机与192.168.1.200的连接)

lsof -i @192.168.1.200

2.3.5 组合过滤(协议+端口+IP,实战常用)

示例1:查看TCP协议、80端口的所有连接(Nginx的HTTP服务)

lsof -i TCP:80

示例2:查看本地IP为192.168.1.100、TCP协议、443端口的连接(Nginx的HTTPS服务)

lsof -i TCP@192.168.1.100:443

示例3:查看远程IP为192.168.1.200、TCP协议、22端口的连接(本机与远程的SSH连接)

lsof -i TCP@192.168.1.200:22

2.3.6 查看监听状态的网络连接(-i -sTCP:LISTEN)

场景:查看本机正在监听的端口(即对外提供服务的端口),类似netstat -tuln。

# 查看所有监听状态的TCP连接(常用)
lsof -i -sTCP:LISTEN

# 查看所有监听状态的UDP连接

lsof -i -sUDP:LISTEN

# 查看80端口的监听状态(确认Nginx是否正常监听)

lsof -i :80 -sTCP:LISTEN

说明:-s参数用于指定协议状态,TCP的常见状态有LISTEN(监听)、ESTABLISHED(已建立连接)、TIME_WAIT(等待关闭)等。

2.4 其他常用参数

2.4.1 -t:只输出PID(方便批量操作)

语法:lsof -t [其他参数],只输出进程ID,不输出其他字段,常用于批量杀死进程。

示例1:查看占用80端口的进程PID,然后批量杀死

# 查看占用80端口的PID
lsof -t -i :80

# 杀死占用80端口的所有进程(慎用,确认是无用进程再执行)

lsof -t -i :80 | xargs kill -9

示例2:查看nginx用户的所有进程PID,批量重启(假设nginx进程重启命令为systemctl restart nginx,此处仅示例批量杀死)

lsof -t -u nginx | xargs kill -9

2.4.2 -a:逻辑与(AND),多条件过滤

语法:lsof -a [条件1] [条件2],表示同时满足两个条件的结果(默认是逻辑或OR)。

示例1:查看root用户且PID为986的进程打开的文件(同时满足USER=root和PID=986)

lsof -a -u root -p 986

示例2:查看TCP协议且处于ESTABLISHED状态(已建立连接)的连接,且属于sshd进程

lsof -a -c sshd -i TCP -sTCP:ESTABLISHED

2.4.3 -n:不解析主机名(加速输出)

语法:lsof -n [其他参数],查看网络连接时,不将IP解析为主机名,可加快命令执行速度(尤其是网络环境差的情况下)。

# 查看80端口连接,不解析主机名(NAME字段显示IP,不显示主机名)
lsof -n -i :80

2.4.4 -P:不解析端口名(加速输出)

语法:lsof -P [其他参数],查看网络连接时,不将端口号解析为端口名称(如22解析为ssh,80解析为http),加速输出。

# 查看80端口连接,不解析端口名(NAME字段显示:80,不显示:http)
lsof -P -i :80

常用组合:lsof -nP -i :80(不解析主机名和端口名,最快查看80端口占用)。

第三部分:实战场景——手把手解决运维常见问题

掌握了上面的参数,我们结合Rocky Linux运维中最常见的5个场景,实战演练,确保你能学以致用。

场景1:Nginx启动失败,提示“80端口已被占用”(最常见)

问题现象:执行systemctl start nginx,提示“Job for nginx.service failed because the control process exited with error code.”,查看日志(journalctl -u nginx)显示“bind() to 0.0.0.0:80 failed (98: Address already in use)”。

解决步骤:

# 步骤1:查看80端口被哪个进程占用(核心命令)
lsof -nP -i :80

# 假设输出结果如下(PID为1234,进程名为httpd,即Apache进程)

COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   1234 root    4u  IPv4  23456      0t0  TCP *:80 (LISTEN)

# 步骤2:杀死占用80端口的进程(若httpd是无用进程)

kill
 -9 1234

# 步骤3:再次启动Nginx,即可成功

systemctl start nginx

补充:若占用端口的是有用进程(如httpd需要保留),则修改Nginx的监听端口(编辑/etc/nginx/nginx.conf,将listen 80改为listen 8080),重启Nginx即可。

场景2:删除大日志文件后,磁盘空间仍未释放

问题现象:执行rm -rf /var/log/nginx/access.log(该文件大小为100G),然后执行df -h查看,发现/分区空间仍为100%,未释放。

原因:该日志文件被Nginx进程占用,删除后仅删除了目录项(文件名),但进程仍在读取文件内容,文件的inode节点未被释放,因此磁盘空间不释放。

解决步骤:

# 步骤1:查看被删除的文件是否仍被进程占用(核心命令)
lsof /var/log/nginx/access.log

# 假设输出结果如下(NAME字段显示(deleted),说明文件已删除但被进程占用)

COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1567 nginx    5w   REG    8,1 107374182400  1234 /var/log/nginx/access.log (deleted)

# 步骤2:杀死对应的进程(或重启进程,推荐重启,避免影响服务)

# 方法1:杀死单个PID(不推荐,可能有多个nginx进程)

kill
 -9 1567

# 方法2:重启Nginx进程(推荐,优雅释放文件,不影响服务连续性)

systemctl restart nginx

# 步骤3:再次查看磁盘空间,已释放

df
 -h

补充:避免该问题的方法:不要直接rm删除正在被进程占用的日志文件,而是使用echo "" > /var/log/nginx/access.log(清空文件内容,不删除文件,进程仍可正常写入)。

场景3:查看MySQL进程正在操作哪些文件(排查数据读写异常)

问题现象:MySQL进程占用CPU过高,怀疑是某个数据文件或日志文件读写异常,需要查看MySQL进程正在打开哪些文件。

解决步骤:

# 步骤1:查看MySQL进程的PID(MySQL进程名为mysqld)
lsof -t -c mysqld  # 输出PID,假设为2000

# 步骤2:查看该PID打开的所有文件(重点关注TYPE为REG的普通文件,即数据/日志文件)

lsof -p 2000

# 重点关注NAME字段,常见的MySQL文件如下:

# /var/lib/mysql/xxx.frm(表结构文件)

# /var/lib/mysql/xxx.ibd(表数据文件,InnoDB引擎)

# /var/log/mysqld.log(MySQL日志文件)


# 步骤3:过滤出MySQL进程打开的日志文件(精准排查)

lsof -a -p 2000 +d /var/log/mysqld

场景4:排查恶意进程(如挖矿进程)

问题现象:服务器CPU占用100%,top命令查看发现有一个未知进程(如minerd)占用大量CPU,需要查看该进程的行为(打开的文件、网络连接),判断是否为恶意进程。

解决步骤:

# 步骤1:查看未知进程的PID(假设进程名为minerd)
lsof -t -c minerd  # 输出PID,假设为3000

# 步骤2:查看该进程打开的所有文件(判断是否读取恶意配置文件、写入挖矿日志)

lsof -p 3000

# 步骤3:查看该进程的网络连接(判断是否连接外部挖矿服务器)

lsof -nP -a -p 3000 -i

# 若输出结果中NAME字段显示连接外部IP(如192.168.1.300:8888),且该IP是挖矿服务器,则可确认是恶意进程


# 步骤4:杀死恶意进程,并删除对应的可执行文件(根据lsof输出的txt字段找到文件路径)

kill
 -9 3000
rm
 -rf /tmp/minerd  # 假设txt字段显示该进程的可执行文件路径为/tmp/minerd

场景5:查看本机与远程服务器的SSH连接(排查远程登录异常)

问题现象:怀疑有非法IP远程登录本机SSH(22端口),需要查看当前所有SSH连接的远程IP。

解决步骤:

# 方法1:查看所有SSH连接(进程名为sshd,TCP协议,ESTABLISHED状态)
lsof -nP -a -c sshd -i TCP -sTCP:ESTABLISHED

# 输出结果示例(NAME字段显示本地IP:ssh->远程IP:端口,即远程IP为192.168.1.200)

COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    4000 root    4u  IPv4  56789      0t0  TCP 192.168.1.100:22->192.168.1.200:54321 (ESTABLISHED)

# 方法2:只查看远程IP(过滤NAME字段,提取远程IP)

lsof -nP -a -c sshd -i TCP -sTCP:ESTABLISHED | awk '{print $9}' | awk -F'->' '{print $2}' | awk -F':' '{print $1}'

# 若发现未知远程IP(如192.168.1.500),可关闭该连接(杀死对应的PID)

kill
 -9 4000

第四部分:进阶技巧——让lsof更高效

4.1 组合参数快速定位问题

实战中,我们通常会组合多个参数,快速过滤需要的信息,以下是几个常用的组合命令,可直接复制使用:

# 1. 快速查看80端口占用(不解析主机名/端口名,最快)
lsof -nP -i :80

# 2. 查看所有监听端口(类似netstat -tuln)

lsof -nP -i -sTCP:LISTEN

# 3. 查看nginx进程的所有网络连接

lsof -nP -a -c nginx -i

# 4. 查看被删除但仍被进程占用的文件(排查磁盘空间不释放)

lsof | grep deleted

# 5. 查看root用户的所有TCP连接

lsof -nP -a -u root -i TCP

4.2 输出内容保存到文件,便于分析

当lsof输出内容过多时,可将输出保存到文件,后续慢慢分析:

# 将80端口的所有连接信息保存到lsof_80.log文件中
lsof -nP -i :80 > /tmp/lsof_80.log

# 查看文件内容

cat
 /tmp/lsof_80.log

4.3 结合其他命令使用(如grep、awk)

lsof的输出可通过grep、awk过滤,提取更精准的信息:

# 1. 查看所有ESTABLISHED状态的TCP连接(过滤状态)
lsof -nP -i TCP | grep ESTABLISHED

# 2. 提取所有网络连接的远程IP(去重)

lsof -nP -i | awk '{print $9}' | awk -F'->' '{print $2}' | awk -F':' '{print $1}' | sort -u

# 3. 查看nginx进程打开的所有.log文件(过滤日志文件)

lsof -a -c nginx | grep .log

第五部分:总结——lsof核心用法回顾

lsof是Rocky Linux运维中不可或缺的工具,核心功能是“列出所有打开的文件”,本质是“进程与文件的关联探测器”。掌握以下核心点,就能解决80%的运维场景:

  • •
    1. 1. 核心场景:端口占用、文件占用(磁盘空间不释放)、进程行为排查、网络连接异常;
  • •
    1. 2. 最常用参数:-i(网络连接)、-p(PID)、-c(进程名)、-u(用户)、+d/+D(目录)、-t(只输出PID);
  • •
    1. 3. 实战命令:
  • • 查看端口占用:lsof -nP -i :端口号
  • • 查看文件占用:lsof 文件名
  • • 排查磁盘不释放:lsof | grep deleted
  • • 批量杀进程:lsof -t [条件] | xargs kill -9

其实lsof的参数还有很多,但以上内容已经足够应对日常运维工作。建议大家多动手练习,结合实际问题使用,慢慢就能熟练掌握这个“系统侦探”的用法,让你的运维工作更高效、更轻松!

最新文章

随机文章