内容纲要

lsof 是 List Open File 的缩写, 它主要用来获取被进程打开文件的信息,我们都知道,在Linux中,一切皆文件,lsof命令可以查看所有已经打开了的文件,比如: 普通文件,目录,特殊的块文件,管道,socket套接字,设备,Unix域套接字等等。系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。同时,它还可以结合 grep 以及 ps 命令进行更多的高级搜索

lsof 命令可显示系统打开的文件,因为 lsof 需要访问核心内存和各种文件,所以必须以 root 用户的身份运行它才能够充分地发挥其功能。

1.命令格式

lsof [参数][文件]

2.命令功能

用于查看你进程开打的文件,打开文件的进程,进程打开的端口(TCP、UDP)。找回/恢复删除的文件。是十分方便的系统监视工具,因为 lsof 需要访问核心内存和各种文件,所以需要 root 用户执行。

lsof打开的文件可以是:

  1. 普通文件
  2. 目录
  3. 网络文件系统的文件
  4. 字符或设备文件
  5. (函数)共享库
  6. 管道,命名管道
  7. 符号链接
  8. 网络文件(例如:NFS file、网络socket,unix域名socket)
  9. 还有其它类型的文件,等等

3.命令参数

[root@ito-yw-host ~]# lsof -h
lsof 4.87
 latest revision: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
 latest FAQ: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
 latest man page: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
 usage: [-?abhKlnNoOPRtUvVX] [+|-c c] [+|-d s] [+D D] [+|-f[gG]] [+|-e s]
 [-F [f]] [-g [s]] [-i [i]] [+|-L [l]] [+m [m]] [+|-M] [-o [o]] [-p s]
[+|-r [t]] [-s [p:s]] [-S [t]] [-T [t]] [-u s] [+|-w] [-x [fl]] [--] [names]
Defaults in parentheses; comma-separated set (s) items; dash-separated ranges.
  -?|-h list help          -a AND selections (OR)     -b avoid kernel blocks
  -c c  cmd c ^c /c/[bix]  +c w  COMMAND width (9)    +d s  dir s files
  -d s  select by FD set   +D D  dir D tree *SLOW?*   +|-e s  exempt s *RISKY*
  -i select IPv[46] files  -K list tasKs (threads)    -l list UID numbers
  -n no host names         -N select NFS files        -o list file offset
  -O no overhead *RISKY*   -P no port names           -R list paRent PID
  -s list file size        -t terse listing           -T disable TCP/TPI info
  -U select Unix socket    -v list version info       -V verbose search
  +|-w  Warnings (+)       -X skip TCP&UDP* files     -Z Z  context [Z]
  -- end option scan     
  +f|-f  +filesystem or -file names     +|-f[gG] flaGs 
  -F [f] select fields; -F? for help  
  +|-L [l] list (+) suppress (-) link counts < l (0 = all; default = 0)
                                        +m [m] use|create mount supplement
  +|-M   portMap registration (-)       -o o   o 0t offset digits (8)
  -p s   exclude(^)|select PIDs         -S [t] t second stat timeout (15)
  -T qs TCP/TPI Q,St (s) info
  -g [s] exclude(^)|select and print process group IDs
  -i i   select by IPv[46] address: [46][proto][@host|addr][:svc_list|port_list]
  +|-r [t[m<fmt>]] repeat every t seconds (15);  + until no files, - forever.
       An optional suffix to t is m<fmt>; m must separate t from <fmt> and
      <fmt> is an strftime(3) format for the marker line.
  -s p:s  exclude(^)|select protocol (p = TCP|UDP) states by name(s).
  -u s   exclude(^)|select login|UID set s
  -x [fl] cross over +d|+D File systems or symbolic Links
  names  select named files or files on named file systems
Anyone can list all files; /dev warnings disabled; kernel ID check disabled.
  • -a 列出打开文件存在的进程
  • -c<进程名> 列出指定进程所打开的文件
  • -g 列出GID号进程详情
  • -d<文件号> 列出占用该文件号的进程
  • +d<目录> 列出目录下被打开的文件
  • +D<目录> 递归列出目录下被打开的文件
  • -n<目录> 列出使用NFS的文件
  • -i<条件> 列出符合条件的进程。(4、6、协议、:端口、 @ip )
  • -p<进程号> 列出指定进程号所打开的文件
  • -u 列出UID号进程详情
  • -h 显示帮助信息
  • -v 显示版本信息

4.安装

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

yum install -y lsof 

5.输出解析

lsof 命令有很多可选参数,不带任何参数执行 lsof 命令会输出当前所有活跃进程打开的所有文件,由于lsof命令会输出很多信息,在示例中我们查看前10行,对输出字段进行解析

[root@centos-7.9 ~]# lsof | head
COMMAND     PID   TID           USER   FD      TYPE             DEVICE    SIZE/OFF       NODE NAME
systemd       1                 root  cwd       DIR              253,0        4096         64 /
systemd       1                 root  rtd       DIR              253,0        4096         64 /
systemd       1                 root  txt       REG              253,0     1632736   67801506 /usr/lib/systemd/systemd
systemd       1                 root  mem       REG              253,0       20064   33763358 /usr/lib64/libuuid.so.1.3.0
systemd       1                 root  mem       REG              253,0      265576   34448764 /usr/lib64/libblkid.so.1.1.0
systemd       1                 root  mem       REG              253,0       90248   33763451 /usr/lib64/libz.so.1.2.7
systemd       1                 root  mem       REG              253,0      157424   33769169 /usr/lib64/liblzma.so.5.2.2
systemd       1                 root  mem       REG              253,0       23968   33769162 /usr/lib64/libcap-ng.so.0.0.0
systemd       1                 root  mem       REG              253,0       19896   33786740 /usr/lib64/libattr.so.1.1.0

输出结果中列 COMMAND 、PID、TID、USER 分别表示进程名、进程ID、线程ID、所属用户

第一列中 systemd 的进程 ID 是 1,它是系统的守护进程

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 列表示路径或者链接

6、实例

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

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

[root@centos-7.9 ~]# lsof -u gdm,apache
COMMAND     PID   USER   FD      TYPE             DEVICE  SIZE/OFF      NODE NAME
php-fpm    1181 apache  cwd       DIR              253,0      4096        64 /
php-fpm    1181 apache  rtd       DIR              253,0      4096        64 /
php-fpm    1181 apache  txt       REG              253,0   4781848 103960545 /opt/rh/rh-php72/root/usr/sbin/php-fpm
php-fpm    1181 apache  mem       REG              253,0     70008 101418157 /usr/lib64/gconv/libGB.so
省略……
php-fpm    1181 apache    0u      CHR                1,3       0t0      2052 /dev/null
php-fpm    1181 apache    1u      CHR                1,3       0t0      2052 /dev/null
php-fpm    1181 apache    2u      CHR                1,3       0t0      2052 /dev/null
php-fpm    1181 apache    9u     unix 0xffff9fa3e5fa0880       0t0  12179700 /var/opt/rh/rh-php72/run/php-fpm/zabbix.sock
gnome-ses  2418    gdm  cwd       DIR              253,0        97   1444834 /var/lib/gdm
gnome-ses  2418    gdm  rtd       DIR              253,0      4096        64 /
gnome-ses  2418    gdm  txt       REG              253,0    298608 101780481 /usr/libexec/gnome-session-binary
省略……

上面的例子中,lsof -u gdm,apache 命令表示列出 dgm和apache 用户已经打开了的文件

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

lsof -u ^apache | more 

(2)找出被删除依然打开的文件

在一些场景中,你可能会发现磁盘空间满了但找不到占用空间的文件,这很有可能是某些文件虽被删除了,却没有释放磁盘空间,这种情况往往是有进程打开了该文件。那我们如何找到这些删除的文件呢?可以结合 grep 命令找出这种文件。lsof |grep deleted 可找出系统所有的被打开且已删除的文件,你可以加上其他的选项以实现更精细查找,如查找mysql 用户打开并删除的文件 lsof -u mysql |grep deleted 。利用这种特性也可以实现删除文件的恢复,

[root@centos-7.9 ~]# lsof |grep deleted
abrt-watc  1398                 root    4r      REG              253,0       32461  100937591 /var/log/Xorg.0.log (deleted)
rsyslogd   1872                 root    8w      REG              253,0     5028953  104140086 /var/log/cron-20210314 (deleted)
rs:main    1872  1924           root    8w      REG              253,0     5028953  104140086 /var/log/cron-20210314 (deleted)
rs:main    1872  1924           root    9w      REG              253,0   118985294  104140092 /var/log/maillog-20210314 (deleted)
X          2301                 root    4w      REG              253,0       32461  100937591 /var/log/Xorg.0.log (deleted)
llvmpipe-  2301  2361           root    4w      REG              253,0       32461  100937591 /var/log/Xorg.0.log (deleted)
mysqld     2378                mysql    5u      REG              253,0           0   67913255 /tmp/ibBmtyYs (deleted)

利用这种特性也可以实现删除文件的恢复,打开 /var/log/cron-20210314 的进程 id 为1872 ,进入 /proc/1872/fd/ 就可以看到该进程打开的所有文件,已删除的文件在末尾会标注 “(deleted)”,8 是指向/var/log/cron-20210314的,用head 查看下文件查到内容是完好的,现在就很容易恢复了。

[root@centos-7.9 ~]# cd /proc/1872/fd/
[root@centos-7.9 fd]# ll
总用量 0
lr-x------ 1 root root 64 3月  11 2021 0 -> /dev/null
lr-x------ 1 root root 64 3月  11 2021 3 -> anon_inode:inotify
l-wx------ 1 root root 64 3月  11 2021 4 -> /var/log/messages
省略……
l-wx------ 1 root root 64 3月  11 2021 8 -> /var/log/cron-20210314 (deleted)
l-wx------ 1 root root 64 3月  11 2021 9 -> /var/log/maillog-20210314 (deleted)
[root@centos-7.9 fd]# head 8
Mar  7 03:47:02 centos-7.9 run-parts(/etc/cron.daily)[11338]: finished logrotate
Mar  7 03:47:02 centos-7.9 run-parts(/etc/cron.daily)[11297]: starting man-db.cron
Mar  7 03:47:04 centos-7.9 run-parts(/etc/cron.daily)[11354]: finished man-db.cron
省略……
[root@centos-7.9 fd]# 

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

[root@centos-7.9 ~]# lsof -i |head -15
COMMAND     PID    USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
rpcbind    1368     rpc    6u  IPv4     13566      0t0  UDP *:sunrpc 
rpcbind    1368     rpc    7u  IPv4     13567      0t0  UDP *:connendp 
rpcbind    1368     rpc    8u  IPv4     13568      0t0  TCP *:sunrpc (LISTEN)
rpcbind    1368     rpc    9u  IPv6     13569      0t0  UDP *:sunrpc 
rpcbind    1368     rpc   10u  IPv6     13570      0t0  UDP *:connendp 
rpcbind    1368     rpc   11u  IPv6     13571      0t0  TCP *:sunrpc (LISTEN)
avahi-dae  1373   avahi   12u  IPv4     18700      0t0  UDP *:mdns 
avahi-dae  1373   avahi   13u  IPv4     18701      0t0  UDP *:52604 
cupsd      1864    root   10u  IPv6       121      0t0  TCP localhost:ipp (LISTEN)
cupsd      1864    root   11u  IPv4       122      0t0  TCP localhost:ipp (LISTEN)
sshd       1866    root    3u  IPv4     19927      0t0  TCP *:ssh (LISTEN)
sshd       1866    root    4u  IPv6     19929      0t0  TCP *:ssh (LISTEN)
master     2217    root   13u  IPv4     63727      0t0  TCP localhost:smtp (LISTEN)
master     2217    root   14u  IPv6     63728      0t0  TCP localhost:smtp (LISTEN)

(4)列出所有 IPV4/6 网络文件

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

[root@centos-7.9 ~]# lsof -i 4 |head
COMMAND     PID    USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
rpcbind    1368     rpc    6u  IPv4     13566      0t0  UDP *:sunrpc 
rpcbind    1368     rpc    7u  IPv4     13567      0t0  UDP *:connendp 
rpcbind    1368     rpc    8u  IPv4     13568      0t0  TCP *:sunrpc (LISTEN)
avahi-dae  1373   avahi   12u  IPv4     18700      0t0  UDP *:mdns 
avahi-dae  1373   avahi   13u  IPv4     18701      0t0  UDP *:52604 
cupsd      1864    root   11u  IPv4       122      0t0  TCP localhost:ipp (LISTEN)
sshd       1866    root    3u  IPv4     19927      0t0  TCP *:ssh (LISTEN)
master     2217    root   13u  IPv4     63727      0t0  TCP localhost:smtp (LISTEN)
zabbix_ag  3802  zabbix    4u  IPv4     70087      0t0  TCP *:zabbix-agent (LISTEN)

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

[root@centos-7.9 ~]# lsof -i 6 |head
COMMAND     PID    USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
rpcbind    1368     rpc    9u  IPv6     13569      0t0  UDP *:sunrpc 
rpcbind    1368     rpc   10u  IPv6     13570      0t0  UDP *:connendp 
rpcbind    1368     rpc   11u  IPv6     13571      0t0  TCP *:sunrpc (LISTEN)
cupsd      1864    root   10u  IPv6       121      0t0  TCP localhost:ipp (LISTEN)
sshd       1866    root    4u  IPv6     19929      0t0  TCP *:ssh (LISTEN)
master     2217    root   14u  IPv6     63728      0t0  TCP localhost:smtp (LISTEN)
mysqld     2378   mysql   36u  IPv6     39979      0t0  TCP *:mysql (LISTEN)
zabbix_ag  3802  zabbix    5u  IPv6     70088      0t0  TCP *:zabbix-agent (LISTEN)
zabbix_ag  3804  zabbix    5u  IPv6     70088      0t0  TCP *:zabbix-agent (LISTEN)

(5)列出在指定端口上打开的文件**

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

[root@centos-7.9 ~]# lsof -i:22
COMMAND   PID USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
sshd     1866 root    3u  IPv4     19927      0t0  TCP *:ssh (LISTEN)
sshd     1866 root    4u  IPv6     19929      0t0  TCP *:ssh (LISTEN)
sshd    37696 root    3u  IPv4 617315159      0t0  TCP centos-7.9:ssh->10.200.4.33:60638 (ESTABLISHED)

上面例子列出了所有在22号端口上打开的文件,包括IPv4/IPv6监听和1个tcp连接

列出目前连接主机 localhost 上端口为:20,21,22,25,53,80相关的所有文件信息,且每隔3秒不断的执行lsof指令

命令:

lsof -i @localhost:20,21,22,25,53,80  -r  3

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

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

[root@centos-7.9 ~]# lsof -ni TCP
COMMAND     PID    USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
rpcbind    1368     rpc    8u  IPv4     13568      0t0  TCP *:sunrpc (LISTEN)
mysqld     2378   mysql   36u  IPv6     39979      0t0  TCP *:mysql (LISTEN)
sshd      11956    root    3u  IPv4 617470628      0t0  TCP 10.200.52.10:ssh->10.200.4.33:62917 (ESTABLISHED)

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

[root@centos-7.9 ~]# lsof -ni TCP:2379
COMMAND   PID USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
coredns 18408 root    7u  IPv4 247062628      0t0  TCP 192.168.10.201:39484->192.168.10.201:2379 (ESTABLISHED)
coredns 18408 root    8u  IPv4 247149626      0t0  TCP 192.168.10.201:39486->192.168.10.201:2379 (ESTABLISHED)
coredns 18408 root    9u  IPv4 247079604      0t0  TCP 192.168.10.201:39488->192.168.10.201:2379 (ESTABLISHED)
etcd    23441 etcd    6u  IPv6  98156846      0t0  TCP *:2379 (LISTEN)
etcd    23441 etcd   11u  IPv4  98156848      0t0  TCP 127.0.0.1:33226->127.0.0.1:2379 (ESTABLISHED)
etcd    23441 etcd   12u  IPv6  98156849      0t0  TCP 127.0.0.1:2379->127.0.0.1:33226 (ESTABLISHED)
etcd    23441 etcd   13u  IPv6 247086177      0t0  TCP 192.168.10.201:2379->192.168.10.201:39484 (ESTABLISHED)
etcd    23441 etcd   14u  IPv6 247086178      0t0  TCP 192.168.10.201:2379->192.168.10.201:39486 (ESTABLISHED)
etcd    23441 etcd   15u  IPv6 247086180      0t0  TCP 192.168.10.201:2379->192.168.10.201:39488 (ESTABLISHED)

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

[root@centos-7.9 ~]# lsof -ni TCP:1-1024

列出谁在使用某个特定的udp端口,命令:

lsof -i udp:5500
Shell

或者:特定的tcp端口,命令:

lsof -i tcp:8081

(7)列出所有网络文件系统

命令:

lsof -N

(8)列出在特定目录打开的文件

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

  • +D 选项会列出一个目录和其子目录中打开的文件
[root@centos-7.9 ~]# lsof +D /home/mysql/lib/mysql
COMMAND  PID  USER   FD   TYPE DEVICE    SIZE/OFF      NODE NAME
mysqld  2378 mysql  cwd    DIR  253,2        4096 268665313 /home/mysql/lib/mysql
mysqld  2378 mysql    3uW  REG  253,2    50331648 268665315 /home/mysql/lib/mysql/ib_logfile0
mysqld  2378 mysql    4uW  REG  253,2    18874368 268826238 /home/mysql/lib/mysql/zabbix/events.ibd
mysqld  2378 mysql    9uW  REG  253,2    50331648 268665316 /home/mysql/lib/mysql/ib_logfile1
mysqld  2378 mysql   10uW  REG  253,2   146800640 268665314 /home/mysql/lib/mysql/ibdata1
mysqld  2378 mysql   11uW  REG  253,2 35001466880 268826226 /home/mysql/lib/mysql/zabbix/history_uint.ibd
略……
  • +d 选项只会列出当前目录下已打开的文件
[root@centos-7.9 ~]# lsof +d /home/mysql/lib/mysql
COMMAND  PID  USER   FD   TYPE DEVICE  SIZE/OFF      NODE NAME
mysqld  2378 mysql  cwd    DIR  253,2      4096 268665313 /home/mysql/lib/mysql
mysqld  2378 mysql    3uW  REG  253,2  50331648 268665315 /home/mysql/lib/mysql/ib_logfile0
mysqld  2378 mysql    9uW  REG  253,2  50331648 268665316 /home/mysql/lib/mysql/ib_logfile1
mysqld  2378 mysql   10uW  REG  253,2 146800640 268665314 /home/mysql/lib/mysql/ibdata1
mysqld  2378 mysql   19uW  REG  253,2  79691776 268665280 /home/mysql/lib/mysql/ibtmp1

lsof 后也可以直接跟逻辑卷或磁盘

[root@centos-7.9 ~]# lsof /dev/mapper/centos-root

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

进程ID是操作系统进程的唯一标识,如果想要知道某进程打开的文件可以使用 lsof -p PID命令查询

[root@centos-7.9 ~]# lsof -p 41927
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF      NODE NAME
nginx   41927 root  cwd    DIR              253,0     4096        64 /
nginx   41927 root  rtd    DIR              253,0     4096        64 /
nginx   41927 root  txt    REG              253,0  1215088  34272922 /usr/sbin/nginx
nginx   41927 root  mem    REG              253,0    27624   2489009 /usr/lib64/perl5/vendor_perl/auto/nginx/nginx.so
nginx   41927 root    7u  IPv6          179578988      0t0       TCP *:webcache (LISTEN)
nginx   41927 root    8u  unix 0xffff9fb1486c6e80      0t0 179580272 socket
nginx   41927 root    9u  unix 0xffff9fb1486c6a40      0t0 179580273 socket
nginx   41927 root   10u  unix 0xffff9fb1486c61c0      0t0 179580274 socket

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

lsof -p 1,2,3,^4 

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

(10)列出某个程序进程所打开的文件信息

命令:

lsof -c mysql
Shell

说明:

  • -c 选项将会列出所有以mysql这个进程开头的程序的文件,其实你也可以写成 lsof | grep mysql, 但是第一种方法明显比第二种方法要少打几个字符了

列出多个进程多个打开的文件信息

命令:

lsof -c mysql -c apache

(11)据文件描述列出对应的文件信息

命令:

lsof -d description(like 2)
Shell

例如:lsof -d txt
例如:lsof -d 1
例如:lsof -d 2
说明:
0表示标准输入,1表示标准输出,2表示标准错误,从而可知:所以大多数应用程序所打开的文件的 FD 都是从 3 开始

根据文件描述范围列出文件信息

命令:

lsof -d 2-3
Shell

列出COMMAND列中包含字符串”sshd”,且文件描符的类型为txt的文件信息

命令:

lsof -c sshd -a -d txt

(12)杀死特定条件的进程

在某些情况我们可能希望结束占用特定目录的进程,可以结合kill命令使用,具体的命令如下

kill -9 `lsof -t -u zabbix` 
kill -9 `lsof -t +D /home/mysql`
  • -t 选项之后表示结果只列出PID列,也就是进程ID列,其他列都忽略