简介

lsof(list open files)是一个列出当前系统打开文件的工具,在Unix中一切(包括网络套接口)都是文件。有趣的是,lsof也是有着最多开关的Linux/Unix命令之一。它有那么多的开关,它有许多选项支持使用-和+前缀。
 


选项    描述 -a    列出打开文件存在的进程; -c<进程名>    列出指定进程所打开的文件; -g    列出GID号进程详情; -d<文件号>    列出占用该文件号的进程; +d<目录>    列出目录下被打开的文件; +D<目录>    递归列出目录下被打开的文件; -n<目录>    列出使用NFS的文件; -i<条件>    列出符合条件的进程。(4、6、协议、:端口、 @ip ) -p<进程号>    列出指定进程号所打开的文件; -u    列出UID号进程详情; -h    显示帮助信息; -v    显示版本信息。


 

关键字段含义


lsof 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


 

 

FD文件描述符列表
 


cwd:表示current work dirctory,即:应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改
txt:该类型的文件是程序代码,如应用程序二进制文件本身或共享库,如上列表中显示的 /sbin/init 程序
lnn:library references (AIX)(库引用);
er:FD information error (see NAME column)(fd信息错误);
jld:jail directory (FreeBSD)(监控目录);
ltx:shared library text (code and data)(共享库文本);
mxx :hex memory-mapped type number xx(十六进制内存映射类型号xx);
m86:DOS Merge mapped file(DOS合并映射文件);
mem:memory-mapped file(内存映射文件);
mmap:memory-mapped device(内存映射设备);
pd:parent directory(父目录);
rtd:root directory(跟目录);
tr:kernel trace file (OpenBSD)(内核跟踪文件);
v86 VP/ix mapped file(VP/IX映射文件);
0:表示标准输出
1:表示标准输入
2:表示标准错误


 

一般在标准输出、标准错误、标准输入后还跟着文件状态模式:
 


u:表示该文件被打开并处于读取/写入模式。 r:表示该文件被打开并处于只读模式。 w:表示该文件被打开并处于。 空格:表示该文件的状态模式为unknow,且没有锁定。 -:表示该文件的状态模式为unknow,且被锁定。


同时在文件状态模式后面,还跟着相关的锁:
 


N:for a Solaris NFS lock of unknown type(对于未知类型的Solaris NFS锁);
r:for read lock on part of the file(用于对文件的一部分进行读取锁定);
R:for a read lock on the entire file(整个文件的读取锁定);
w:for a write lock on part of the file;(文件的部分写锁)
W:for a write lock on the entire file;(整个文件的写锁)
u:for a read and write lock of any length(对于任意长度的读写锁);
U:for a lock of unknown type(对于未知类型的锁);
x:for an SCO OpenServer Xenix lock on part of the file(对于文件的sco openserver xenix锁);
X:for an SCO OpenServer Xenix lock on the entire file(对于整个文件的sco openserver xenix锁);
space:if there is no lock(如果没有锁).


2.1.2 文件类型:
 


DIR:表示目录。 CHR:表示字符类型。 BLK:块设备类型。 UNIX: UNIX 域套接字。 FIFO:先进先出 (FIFO) 队列。 IPv4:网际协议 (IP) 套接字。 DEVICE:指定磁盘的名称 SIZE:文件的大小 NODE:索引节点(文件在磁盘上的标识) NAME:打开文件的确切名称


 

lsof使用实例

1.列出所有打开的文件:

lsof

备注: 如果不加任何参数,就会打开所有被打开的文件,建议加上一下参数来具体定位

2. 查看谁正在使用某个文件

lsof access_nginx.log

3.显示目录下被进程开启的文件

lsof +d /usr/local/

4. 比使用+D选项,遍历查看某个目录的所有文件信息 的方法

lsof +D /usr/local/  

5. 列出某个用户打开的文件信息

lsof  -u username

备注: -u 选项,u其实是user的缩写

6. 列出某个程序所打开的文件信息

lsof -c mysql

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

7. 列出多个程序多打开的文件信息

lsof -c mysql -c apache

8. 列出某个用户以及某个程序所打开的文件信息

lsof -u test -c mysql

9. 列出除了某个用户外的被打开的文件信息

lsof   -u ^root

备注:^这个符号在用户名之前,将会把是root用户打开的进程不让显示

10. 通过某个进程号显示该进行打开的文件

lsof -p 1

11. 列出多个进程号对应的文件信息

lsof -p 123,456,789

12. 列出除了某个进程号,其他进程号所打开的文件信息

lsof -p ^1

13 . 列出所有的网络连接

lsof -i

14. 列出所有tcp 网络连接信息

lsof  -i tcp

15. 列出所有udp网络连接信息

lsof  -i udp

16. 列出谁在使用某个端口

lsof -i :3306

17. 列出谁在使用某个特定的udp端口

lsof -i udp:55

特定的tcp端口

lsof -i tcp:80

18. 列出某个用户的所有活跃的网络端口

lsof  -a -u test -i

19. 列出所有网络文件系统

lsof -N

20.域名socket文件

lsof -u

21.某个用户组所打开的文件信息

lsof -g 5555

22. 根据文件描述列出对应的文件信息,显示使用fd为4的进程

lsof -d 4

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

lsof -d 2-3

 

场景一 有时可以通过lsof恢复删除的文件

 

原理:

当进程打开了某个文件时,只要该进程保持打开该文件,即使将其删除,它依然存在于磁盘中。这意味着,进程并不知道文件已经被删除,它仍然可以向打开该文件时提供给它的文件描述符进行读取和写入。除了该进程之外,这个文件是不可见的,因为已经删除了其相应的目录索引节点。

在/proc 目录下,其中包含了反映内核和进程树的各种文件。/proc目录挂载的是在内存中所映射的一块区域,所以这些文件和目录并不存在于磁盘中,因此当我们对这些文件进行读取和写入时,实际上是在从内存中获取相关信息。大多数与 lsof 相关的信息都存储于以进程的 PID 命名的目录中,即 /proc/20996 中包含的是 PID 为 20996的进程的信息。每个进程目录中存在着各种文件,它们可以使得应用程序简单地了解进程的内存空间、文件描述符列表、指向磁盘上的文件的符号链接和其他系统信息。lsof 程序使用该信息和其他关于内核内部状态的信息来产生其输出。

 

实践:

当我们不小心误删了某个文件比如 access_nginx.log,只要这个时候系统中还有进程正在访问该文件,那么我们就可以通过lsof从/proc目录下恢复该文件的内容。

恢复的方法如下:

首先使用lsof来查看当前是否有进程打开access_nginx.log文件,如下:


lsof |grep -E 'FD|access_nginx'
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 20996 root 14w REG 253,1 351016 49298 /data/wwwlogs/access_nginx.log (deleted)
nginx 29177 www 14w REG 253,1 351016 49298 /data/wwwlogs/access_nginx.log (deleted)
nginx 29178 www 14w REG 253,1 351016 49298 /data/wwwlogs/access_nginx.log (deleted)


 

PID 20996 打开文件的文件描述符为14w。状态为deleted。因此我们可以在 /proc/20996/fd/14(fd下的每个以数字命名的文件表示进程对应的文件描述符)中查看相应的信息,如下:


head -n 10 /proc/20996/fd/14 
182.254.52.17 - - [28/May/2020:04:25:16 +0800] "GET http://154.8.236.121/?id%3D17 HTTP/1.1" 200 4743 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0"
60.191.52.254 - - [28/May/2020:04:49:26 +0800] "HEAD http://112.124.42.80:63435/ HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"


 


cat /proc/20996/fd/14 > access_nginx.log


 

恢复完毕

 

场景二 too many open files报错,查看哪些程序打开了很多文件

 

网上很多介绍用下面命令,其实是不准确得


lsof -n |awk '{print $2}'|sort|uniq -c |sort -nr|head -n 5


 

应该用下面得命令

查看哪个进程使用的fd最多:


find /proc -print | grep -P '/proc/\d+/fd/'| awk -F '/' '{print $3}' | uniq -c | sort -rn | head


 

查看fd使用总数:


cat /proc/sys/fs/file-nr


或者(结果多的时候运行需要一段时间)
find /proc -print | grep -P '/proc/\d+/fd/'| wc -l