lsof 命令详解
lsof 是 List Open File 的缩写, 它主要用来获取被进程打开文件的信息,我们都知道,在Linux中,一切皆文件,lsof命令可以查看所有已经打开了的文件,比如: 普通文件,目录,特殊的块文件,管道,socket套接字,设备,Unix域套接字等等。系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。同时,它还可以结合 grep 以及 ps 命令进行更多的高级搜索
lsof 命令可显示系统打开的文件,因为 lsof 需要访问核心内存和各种文件,所以必须以 root 用户的身份运行它才能够充分地发挥其功能。
1.命令格式
lsof [参数][文件]
2.命令功能
用于查看你进程开打的文件,打开文件的进程,进程打开的端口(TCP、UDP)。找回/恢复删除的文件。是十分方便的系统监视工具,因为 lsof
需要访问核心内存和各种文件,所以需要 root
用户执行。
lsof
打开的文件可以是:
- 普通文件
- 目录
- 网络文件系统的文件
- 字符或设备文件
- (函数)共享库
- 管道,命名管道
- 符号链接
- 网络文件(例如:NFS file、网络socket,unix域名socket)
- 还有其它类型的文件,等等
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列,其他列都忽略