lsof
一、简介
lsof(list open files)是一个列出当前系统打开文件的工具。在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。
所以如传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字等,系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。
二、详解
2.1、输出信息每列字段含义(root权限)
COMMAND 进程名
PID 进程标识符
USER 进程所有者
FD 文件描述符,应用程序通过文件描述符识别该文件。如cwd、txt等,后文详细列出
TYPE 文件类型,如DIR、REG等
DEVICE 指定磁盘的名称
SIZE 文件的大小(单位:字节Byte)
NODE 索引节点(文件在磁盘上的标识)
NAME 打开文件的确切名称
2.2、参数
语法:lsof [options] filename
lsof filename 显示打开指定文件的所有进程 lsof -a 表示两个参数都必须满足时才显示结果 lsof -c string 显示COMMAND列中包含指定字符的进程所有打开的文件 lsof -u username 显示所属user进程打开的文件 lsof -g gid 显示归属gid的进程情况 lsof +d /DIR/ 显示目录下被进程打开的文件 lsof +D /DIR/ 同上,但是会搜索目录下的所有目录,时间相对较长 lsof -d FD 显示指定文件描述符的进程 lsof -n 不将IP转换为hostname,缺省是不加上-n参数 lsof -i 用以显示符合条件的进程情况 lsof -i[46] [protocol][@hostname|hostaddr][:service|port] 46 --> IPv4 or IPv6 protocol --> TCP or UDP hostname --> Internet host name hostaddr --> IPv4地址 service --> /etc/service中的 service name (可以不只一个) port --> 端口号 (可以不只一个)
2.3、示例
lsof | grep deleted 查看文件没释放的
lsof `which httpd` 哪个进程在使用nginx的可执行文件(which+进程名 可查看进程的执行文件) lsof /etc/passwd 哪个进程在占用/etc/passwd lsof /dev/hda6 哪个进程在占用hda6(/dev/xxx hd-硬盘类型 a-第一块盘 6-第2个逻辑分区,逻辑分区从5开始) lsof /dev/cdrom 哪个进程在占用光驱
lsof -c mysql -c 选项将会列出所有以mysql开头的程序的文件(-c mysql -c nginx 可查看多个进程打开的文件) lsof -c courier -u ^zahn 显示出那些文件被以courier打头的进程打开,但是并不属于用户zahn lsof -p 30297 显示那些文件被pid为30297的进程打开
lsof -p 进程号 -nP | grep TCP 查看进程连接情况(-nP参数用于将ip地址和端口号显示为正常的数值类型,否则可能会用别名表示) lsof -D /tmp/test 递归查看某个目录的文件信息
lsof -U 显示所有socket文件
lsof -a -u root -i 列出root用户所有活跃的网络端口 lsof -u1000 查看uid是100的用户的进程的文件使用情况 lsof -utony 查看用户tony的进程的文件使用情况 lsof -u^tony 查看不是用户tony的进程的文件使用情况(^是取反的意思)
lsof -i 显示所有打开的端口 lsof -i:80 显示所有打开80端口的进程 lsof -i -U 显示所有打开的端口和UNIX domain文件
lsof -i tcp 列出所有tcp网络连接信息
lsof -i udp 列出所有udp网络连接信息 lsof -i UDP@[url]www.baidu.com:123 显示那些进程打开了到www.baidu.com的UDP的123(ntp)端口的链接 lsof -i tcp@ohaha.ks.edu.tw:ftp -r 不断查看目前ftp连接的情况(-r,lsof会永远不断的执行,直到收到中断信号,+r,lsof会一直执行,直到没有档案被显示,缺省是15s刷新) lsof -i tcp@ohaha.ks.edu.tw:ftp -n lsof -n 不将IP转换为hostname,缺省是不加上-n参数
2.4、使用lsof恢复删除的进程使用的文件(必须是有进程在使用这个文件,且是被delete但是仍然是open的文件)
原理:在Linux系统的/proc 分区下保存着进程的目录和名字,包含fd(文件描述符)和其下的子目录(进程打开文件的链接),那么如果删除了一个文件,还存在一个 inode的引用,
当不小心用了 rm -f 删除文件时,其实只是删除了文件的目录索引节点,对于文件系统不可见,但是对于打开它的进程依然可见,就可以使用I/O重定向的方式来恢复文件。
示例:以/var/log/messages 为例
#测试前先cp,养成好习惯
cp /var/log/messages /var/log/messages.bak
#删除文件 rm -f /var/log/messages
#查看这个文件信息(/proc/进程号/fd/文件描述符) lsof | grep /var/log/messages
#查看/proc对应留存的信息,比对拷贝的信息 cat /proc/225/fd/4
cat /var/log/messages
#重定向恢复文件
cat /proc/225/fd/4 > /var/log/messages
2.5、每字段含义详解
1)文件描述符
内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
常见内容有 cwd、rtd、txt、mem 和一些数字等等。其中 cwd 表示当前的工作目录;rtd 表示根目录;txt 表示程序的可执行文件;mem 表示内存映射文件
还有一部分 FD 是以数字表示的,如标准输入输出文件,数字后面的字母表示进程对该文件的读写模式,比如上图中的 u 表示该文件被打开并处于读取/写入模式。除了 u,还有 r 表示只读模式,w 表示只写模式,还可以同时应用 W 表示该进程拥有对文件写操作的锁
2)文件类型
DIR:表示目录
CHR:表示字符类型
BLK:块设备类型
UNIX: UNIX 域套接字
FIFO:先进先出 (FIFO) 队列
IPv4:网际协议 (IP) 套接字
3)文件大小单位换算
1 Byte = 8 Bits(即 1B=8b) 1 KB = 1024 Bytes 1 MB = 1024 KB 1 GB = 1024 MB 1 TB = 1024 GB
三、补充
3.1 文件描述符&文件句柄
#查看当前使用的文件句柄数 #三列数据分别为:已分配文件句柄的数目,已分配未使用文件句柄的数目,文件句柄的最大数目 cat /proc/sys/fs/file-nr #查看当前已使用的文件描述符数 lsof -P -n| wc -l
两条命令有较大差距,原因是:
file-nr文件里面的第一个字段代表的是内核分配的struct file的个数,也就是文件句柄个数,而不是文件描述符。
lsof的结果包含了并非以fd形式打开的文件,比如用mmap方式访问文件(fd一栏显示为mem),实际并不占用fd。其中包括了像.so和.jar文件,也是以fd为mem和具体fd编号分别打开了一次
lsof是通过查看进程的内存映射和文件描述符表来枚举打开文件的, 如果是一个多线程的服务。主线程先退出了,子线程还活着, 那么进程的fd表看起来就是空的
lsof看到的是文件描述符不能代表文件句柄
查看哪个进程的文件描述符最多:
#fd数量
find /proc -print | grep -P '/proc/\d+/fd/'| awk -F '/' '{print $3}' | uniq -c | sort -rn | head
lsof | awk '{print $2}' | uniq -c | sort -rnk1
#具体进程的fd数
ls -l /proc/<pid>/fd | wc -l
3.2 lsof: no pwd entry for UID 70
今天在清理磁盘的时候,执行 lsof | grep deleted 时,出现很多 lsof: no pwd entry for UID 70 的报错,网上查原因有两个:
1、进程在用户被删除之前启动,并且从那以后一直在运行
2、进程在容器内被启动(该UID为容器内的用户ID)
可以使用-w参数忽略这些错误 lsof -w | grep deleted