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:打开文件的确切名称
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