Linux下 lsof 命令详解


lsof 是 List Open File 的缩写, 它主要用来获取被进程打开文件的信息,我们都知道,在Linux中,一切皆文件,lsof命令可以查看所有已经打开了的文件,比如: 普通文件,目录,特殊的块文件,管道,socket套接字,设备,Unix域套接字等等,同时,它还可以结合 grep 以及 ps 命令进行更多的高级搜索

安装

lsof 命令默认是没有安装的,而且它的使用需要有root权限或者赋予普通用于sudo权限, 使用以下命令安装

yum install -y lsof

lsof 命令有很多可选参数,本文根据我自己的使用经验整理了一些比较常用且重要的用法

列出所有打开的文件

不带任何参数执行 lsof 命令会输出当前所有活跃进程打开的所有文件

[root@ecs-centos-7 ~]# lsof | more
COMMAND     PID   TID    USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
systemd       1          root  cwd       DIR              253,1      4096          2 /
systemd       1          root  rtd       DIR              253,1      4096          2 /
systemd       1          root  txt       REG              253,1   1624520     530313 /usr/lib/systemd/systemd
systemd       1          root  mem       REG              253,1     20064     528340 /usr/lib64/libuuid.so.1.3.0
systemd       1          root  mem       REG              253,1    265600     532853 /usr/lib64/libblkid.so.1.1.0
systemd       1          root  mem       REG              253,1     90248     525942 /usr/lib64/libz.so.1.2.7
systemd       1          root  mem       REG              253,1    157424     525955 /usr/lib64/liblzma.so.5.2.2
systemd       1          root  mem       REG              253,1     23968     526159 /usr/lib64/libcap-ng.so.0.0.0
systemd       1          root  mem       REG              253,1     19896     526135 /usr/lib64/libattr.so.1.1.0
systemd       1          root  mem       REG              253,1     19288     525996 /usr/lib64/libdl-2.17.so
systemd       1          root  mem       REG              253,1    402384     525931 /usr/lib64/libpcre.so.1.2.0
systemd       1          root  mem       REG              253,1   2156160     

由于lsof命令会输出很多信息,所以上面例子中使用了 lsof | more 来分页显示命令输出结果

输出结果中,第一列中 systemd 的进程ID是 1,它是一个守护进程

其中列 COMMANDPIDUSER 分别表示进程名、进程ID、所属用户

FD 是文件描述符,下面是可能的类型以及说明

FD 说明
cwd 当前目录
txt txt文件
rtd root目录
mem 内存映射文件

TYPE 是文件类型,下面是可能的值以及说明

TYPE 说明
DIR 目录
REG 普通文件
CHR 字符
a_inode Inode文件
FIFO 管道或者socket文件
netlink 网络
unknown 未知

DEVICE 表示设备ID

SIZE/OFF 表示进程大小

NODE 表示文件的Inode号

NAME 表示路径或者链接

列出指定用户已打开的文件

使用 -u 选项可以列出指定用户已经打开的文件,该选项后面可以接多个用户名,每个用户名之间用空格隔开,表示列出所有指定用户已打开的所有文件

[root@ecs-centos-7 ~]# lsof -u tt | more
COMMAND   PID USER   FD   TYPE DEVICE  SIZE/OFF   NODE NAME
bash    27789   tt  cwd    DIR  253,1      4096 131090 /home/tt
bash    27789   tt  rtd    DIR  253,1      4096      2 /
bash    27789   tt  txt    REG  253,1    964600 525779 /usr/bin/bash
vim     27813   tt  txt    REG  253,1   2337192 531847 /usr/bin/vim
vim     27813   tt    4u   REG  253,1     12288 131167 /home/tt/.p.txt.swp

上面的例子中,lsof -u tt 命令表示列出 tt 用户已经打开了的文件,从结果可以看出,用户打开了 /home/tt//usr/bin/bash/usr/bin/vim /home/tt/.p.txt.swp 这几个文件

如果要排除指定用户已经打开的文件,可以在用户名前加 ^ 符号,下面的命令会列出除tt用户外其他所有用户已打开了的文件

lsof -u ^tt | more 

找出打开着但已被删除了的文件

有这样一种场景,有一个服务正在往日志文件中写日志,这个时候,不小心把正在写入的日志文件删除了

上面的场景中,日志文件虽然被删除了,但是文件仍然是打开着的,它仍然占用文件系统的空间,我们可以结合 grep 命令找出这种打开着,但是已经被删除的文件

[root@ecs-centos-7 ~]# lsof -u tt | grep deleted
vim     27813   tt    4u   REG  253,1    12288 131167 /home/tt/.p.txt.swp(deleted)

上面例子中使用 lsof -u tt | grep deleted 命令查看用户 tt打开着的确被删除的文件

从结果可以看出,在往 p.txt写入内容的时候,文件被删除了

列出所有打开了的网络文件

[root@ecs-centos-7 ~]# lsof -i
COMMAND    PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ntpd       567   ntp   18u  IPv4  12657      0t0  UDP localhost:ntp
ntpd       567   ntp   22u  IPv6  16095      0t0  UDP ecs-centos-7.4-64bit-20200212:ntp 
dhclient   651  root    6u  IPv4  14594      0t0  UDP *:bootpc 
master     960  root   13u  IPv4  15791      0t0  TCP localhost:smtp (LISTEN)
master     960  root   14u  IPv6  15792      0t0  TCP localhost:smtp (LISTEN)
mysqld    1053 mysql   13u  IPv6  15147      0t0  TCP *:mysql (LISTEN)
sshd      1348  root    3u  IPv4  16698      0t0  TCP *:ssh (LISTEN)
  • 列出所有 IPV4/6 网络文件

列出所有已经打开了的 ipv4 网络文件

[root@ecs-centos-7 ~]# lsof -i 4
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ntpd       567  ntp   16u  IPv4  12651      0t0  UDP *:ntp 
ntpd       567  ntp   18u  IPv4  12657      0t0  UDP localhost:ntp 
ntpd       567  ntp   21u  IPv4  16094      0t0  UDP ecs-centos-7.4-64bit-20200212:ntp 
dhclient   651 root    6u  IPv4  14594      0t0  UDP *:bootpc 
master     960 root   13u  IPv4  15791      0t0  TCP localhost:smtp (LISTEN)
sshd      1348 root    3u  IPv4  16698      0t0  TCP *:ssh (LISTEN)

所有已经打开了的 ipv6 网络文件

[root@ecs-centos-7 ~]# lsof -i 6
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
ntpd     567   ntp   17u  IPv6  12652      0t0  UDP *:ntp 
ntpd     567   ntp   19u  IPv6  12658      0t0  UDP localhost:ntp 
ntpd     567   ntp   22u  IPv6  16095      0t0  UDP ecs-centos-7.4-64bit-20200212:ntp 
master   960  root   14u  IPv6  15792      0t0  TCP localhost:smtp (LISTEN)
mysqld  1053 mysql   13u  IPv6  15147      0t0  TCP *:mysql (LISTEN)
sshd    1348  root    4u  IPv6  16700      0t0  TCP *:ssh (LISTEN)
  • 列出在指定端口上打开的文件

使用 lsof -i:端口号 可以获得所有在指定端口号上打开的文件

[root@ecs-centos-7 ~]# lsof -i:22
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd     1348 root    3u  IPv4  16698      0t0  TCP *:ssh (LISTEN)
sshd     1348 root    4u  IPv6  16700      0t0  TCP *:ssh (LISTEN)
sshd    27741 root    3u  IPv4 458958      0t0  TCP ecs-centos-7.4-64bit-20200212:ssh->113.118.121.220:42395 (ESTABLISHED)
sshd    27819 root    3u  IPv4 459250      0t0  TCP ecs-centos-7.4-64bit-20200212:ssh->113.118.121.220:19807 (ESTABLISHED)
sshd    27895 root    3u  IPv4 459828      0t0  TCP

上面例子列出了所有在22号端口上打开的文件

在服务器开发中,经常会部署一个网关或者代理程序,用来和客户端通讯,网关或者代理程序需要开放一个固定的端口供客户端连接用

如果客户端连接不上网关或者代理程序,我们可以用上述命令检查网关或代理程序的端口是否开启,来排除因为端口关闭了导致连接不上网关的情况

  • 列出使用了指定协议(TCP/UDP) 的文件

使用 lsof -i TCP/UDP 列出使用了TCP 或 UDP 协议的文件

[root@cghost8 /home/cgyx]# lsof -i TCP | more
COMMAND      PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
sshd        1704   root    3u  IPv4   13593      0t0  TCP *:ssh (LISTEN)
sshd        1704   root    4u  IPv6   13595      0t0  TCP *:ssh (LISTEN)
redis-serer   1725   root    4u  IPv4   19773      0t0  TCP localhost:6380 (LISTEN)
nc          2067   cgyx    4u  IPv4   39167      0t0  TCP *:60600 (LISTEN)
mysqld      3020  mysql    4u  IPv6 5514608      0t0  TCP 192.168.70.10:mysql->192.168.70.10:37084 (ESTABLISHED)

使用 lsof -i TCP:3306 列出使用了TCP 协议并且端口为3306的文件

[root@cghost8 /home/cgyx]# lsof -i TCP:3306
COMMAND      PID  USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
mysqld      3020 mysql    4u  IPv6 5514608      0t0  TCP 192.168.70.10:mysql->192.168.70.10:37084 (ESTABLISHED)

使用 lsof -i TCP:1-1024 列出使用了TCP协议并且端口范围为 1 到 1024 的文件

[root@cghost8 /home/cgyx]# lsof -i TCP:1-1024
COMMAND   PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
sshd     1704   root    3u  IPv4   13593      0t0  TCP *:ssh (LISTEN)
sshd     1704   root    4u  IPv6   13595      0t0  TCP *:ssh (LISTEN)
cupsd    1709   root   12u  IPv6   39148      0t0  TCP localhost:ipp (LISTEN)
cupsd    1709   root   13u  IPv4   39149      0t0  TCP localhost:ipp (LISTEN)
smbd     1824   root   35u  IPv6   17658      0t0  TCP *:microsoft-ds (LISTEN)
smbd     1824   root   36u  IPv6   17659      0t0  TCP *:netbios-ssn (LISTEN)
smbd     1824   root   37u  IPv4   17660      0t0  TCP *:microsoft-ds (LISTEN)
smbd     1824   root   38u  IPv4   17661      0t0  TCP *:netbios-ssn (LISTEN)

列出目录中所有打开的文件

可以使用lsof命令列出指定目录中的所有打开文件

现有一个data目录 ,结构如下:

[root@ecs-centos-7 tt]# tree data/
data/
├── dira
│   └── a.txt
└── d.s

1 directory, 2 files

列出 data 目录中打开的文件

[root@ecs-centos-7 tt]# lsof +D ./data/
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash    28473 root  cwd    DIR  253,1     4096 131146 ./data
bash    28502 root  cwd    DIR  253,1     4096 131172 ./data/dira
vim     28530 root  cwd    DIR  253,1     4096 131172 ./data/dira
vim     28530 root    4u   REG  253,1    12288 131174 ./data/dira/.a.txt.swp

[root@ecs-centos-7 tt]# lsof +d ./data/
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash    28473 root  cwd    DIR  253,1     4096 131146 ./data
bash    28502 root  cwd    DIR  253,1     4096 131172 ./data/dira
vim     28530 root  cwd    DIR  253,1     4096 131172 ./data/dira

上面例子中,+D+d 选项都是列出目录中打开的文件

+D 选项会列出一个目录和其子目录中打开的文件,而 +d 选项只会列出当前目录下已打开的文件

列出指定进程ID打开的文件

进程ID是操作系统进程的唯一标识,以下命令列出了进程ID为 1053 相关的文件, 从结果中可以知道这个进程ID对应的进程是MySQL

[root@ecs-centos-7 ~]# lsof -p 1053
COMMAND  PID  USER   FD   TYPE             DEVICE  SIZE/OFF    NODE NAME
mysqld  1053 mysql  cwd    DIR              253,1      4096 1055765 /var/lib/mysql
mysqld  1053 mysql  rtd    DIR              253,1      4096       2 /
mysqld  1053 mysql  txt    REG              253,1 251841448  534935 /usr/sbin/mysqld
mysqld  1053 mysql  mem    REG              253,1    209512  659436 /usr/lib64/mysql/plugin/validate_password.so
mysqld  1053 mysql    1w   REG              253,1    206658  924771 /var/log/mysqld.log
mysqld  1053 mysql    2w   REG              253,1    206658  924771 /var/log/mysqld.log

上述命令中,-p 选项后面可以指定多个进程ID,每个进程ID之间用逗号分隔,如果想排除掉某个进程打开的文件,可以在该进程ID前面加上 ^符号

lsof -p 1,2,3,^4

上述命令会列出进程1,进程2,进程3打开的所有文件,同时忽略进程4打开的文件

杀死指定用户的所有进程

前面介绍了列出指定用户所有打开的文件,我们可以组合 kill 命令一起使用,实现杀死指定用户的所有进程的功能,具体的命令如下

kill -9 `lsof -t -u tt`

上述命令中,lsof -u tt 是列出tt用户所有打开的文件,加上 -t 选项之后表示结果只列出PID列,也就是进程ID列,其他列都忽略,前面的 kill -9 表示强制结束指定的进程ID

小结

本文介绍了 lsof 命令的一些常见用法,它还有很多其他的用法,请自行查看man文档

posted @ 2021-10-08 13:57  Linux开发那些事儿  阅读(49042)  评论(0编辑  收藏  举报