lsof命令可以列出当前系统打开的文件描述符,由哪个进程打开了哪个文件等信息。因为Linux系统上一切皆文件,所以无论是普通的文件访问还是网络通信都会用到文件描述符或者说都是一个文件。

wKioL1jSaNSg11moAAEqWxWlHkY059.jpg

列名说明
COMMAND进程的名称
PID进程PID号
USER进程的所有者
FD文件描述符,应用程序通过文件描述符识别文件
TYPE

文件类型:

               REG:文件

               DIR:目录

               CHR:字符设备

               BLK:块设备

DEVICE
设备名称
SIZE/OFF
文件大小
NODE
索引节点
NAME

常用参数:

参数
说明
-c COMMAND显示指定COMMAND列中的进程打开的文件
-c -p PID显示制定进程号打开的文件
-u USERNAME显示所属用户进程打开的文件
-g GID显示所属GID进程打开的文件
-d FD显示指定的文件描述符
-i显示网络进程打开的文件
-i PORT显示指定端口打开的文件
+d /DIR显示指定目录被哪个进程打开
+D /DIR
功能同上,但是会搜索目录下所有的目录
-n
显示IP地址而不是主机名
-P
约束网络问卷的端口号到端口名称的转换
-I
约束用户ID到登录名的转换
+M
支持本地TCP或者UDP端口映射程序
-i4/6
显示IPV4或者V6协议下的端口

举例说明:

显示22端口被哪个进程占用以及打开的文件描述符

lsof -i:22 -n

wKioL1jSbJqBwO8JAACg1Lh07U8241.jpg

显示Nginx用户打开哪些文件

lsof -u nginx

wKioL1jSbUfREWw4AACdXujbEMQ345.jpg

显示指定文件被哪些进程所打开

lsof /var/log/nginx/error.log

wKioL1jSbcWinne1AABzld6OBh8081.jpg

显示指定目录下由哪些文件被打开

注意:+d的效果,下面两个命令一样,但是结果不同,说明+d参数不搜索子目录

lsof +d /var/log/

wKioL1jSbjnywK3kAABwQafsHIg970.jpg如果要想搜索子目录就要使用+D参数,但是搜索比较消耗时间

lsof +D /var/

wKioL1jSbrPCiYObAADb7QnKGx0881.jpg

查找那个IP端口访问了那个IP端口,这个在源主机还是目的主机都可以用,下面我想查的是当前这个机器的那个程序访问了112那个主机

lsof -Pnl +M -i4

wKiom1lxZAWicXjXAABaL6ZD108399.jpg

恢复删除文件:

下面的方式只是在特定场景下可以使用。比如删除日志文件,但是磁盘空间没有释放,因为进程还在使用那个文件,虽然你在路径中找不到了,这种情况下你删除文件,其实该文件还是存在的,因为进程不通过文件名称找文件,而是文件描述符,所以对于进程来说它并不知道文件被删除了。

另外删除文件其实只是切断了INODE与块的关系,在位图中标识出该块可用,数据其实还在。如果一个文件正在被进程使用,你删除了的话那么位图是不会更新的,所以内核认为该文件没有删除,所以可用空间不会增长。

举例说明:Nginx的访问日志,我FOR循环2万次不断访问,这样Nginx的日志文件就会不断写入,在写入期间,我删除该文件,然后找回。

首先查看Nginx的日志文件都由哪些进程来使用

wKiom1jSffjxhSviAABKQI_3QYs059.jpg不断监控其大小变化

watch -n 1 du -sh *

wKioL1jSfVjjQvLzAAA2sjAsn_0785.jpg

循环访问开始,日志出现了增长

wKiom1jSg0DApO2sAAAyS-f2g8I811.jpg

删除文件,并没有得到任何提示

wKioL1jSg1yiG82rAAAvPo3ISac673.jpg

再来查看监控大小这边,提示文件找不到了

wKiom1jSg3vwLP5FAABBSFvEjP4616.jpg

查看文件描述符信息,有了一个(deleted)的标签

//通过这个命令就可以查找被程序打开且被删除的文件
lsof | grep deleted

wKioL1jSg5qSKwrVAABQ7gsAHdc097.jpg通过文件描述符查看文件信息

wKiom1jShV3hHW6WAABpcDxTFC0127.jpg

我们知道/proc是个伪文件系统,内容都在内存中,我们这时候通过查看命令就可以看这个文件描述符所指向的内容

head -n 100 /proc/94429/fd/5

wKioL1jShYLQzhzxAADOu0p8Rsg024.jpg

既然可以看其实就可以保存,因为Nginx我这里启动了2个进程,你只需要把所有进程对应的文件描述符通过下面的访问写入到一个文件,就把之前的内容都找回了。

cat /proc/94429/fd/5 >> /var/log/nginx/access_restore.log

wKioL1jShf3Se9SvAADsV13xbeI480.jpg


找到进程

比如B服务器有一些进程连接到A服务器上,此时B服务器作为客户端它的端口都是高位随机端口,你查询到底B服务器上的那个进程连到A服务器上,通过netstat命令或者ps命令是无法查询到的。

首先使用iftop命令,因为你知道对方A服务器上的服务端口和A服务器IP地址,这样你就可以知道B服务器上那个高位随机端口。

iftop -nP

wKiom1kL-LHDGr6nAAEGbhSeOZU488.jpg

因为是高位随机端口所以会变化,但是不会特别快,因为进程打开一个套接字然后关闭不是马上关闭的,这时候我们就可以利用lsof命令来查看并找到PID

lsof -Pnl +M -i4 | grep 43897

wKiom1kL-SPQAUOgAAA3DsBhyIs313.jpg

这时候你已经获得了PID也就是15579,然后再通过ps命令来查询,如下图

wKiom1kL-X6znYn3AAD2RV85WQk106.jpg