7.5 查询进程打开的文件:lsof
lsof(list open files)是一个列出当前系统中所有打开文件的工具。早在第1章中就提到过,Linux中一切皆文件,所以在系统中,被打开的文件可以是普通文件、目录、网络文件系统中的文件、字符设备、管道、socket等。那么如何知晓现在系统打开的是哪些文件呢,这时lsof命令就有用武之地了。不过,这个命令在系统中可能并未默认安装,在CentOS下如果可以联网,简单输入yum install lsof-y即可安装该工具,如果是在RedHat下,则需要到原始安装光盘中寻找lsof的rpm包进行安装。关于如何安装软件包,将在后一章中详细描述。该命令的使用方法如下:
- [root@localhost ~]# lsof
- [options
- ] filename
- #
- 常用的参数列表
- #lsof filename
- 显示打开指定文件的所有进程
- #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
- 或IPv6
- # protocol
- 指TCP
- 或UDP
- # hostname
- 指主机名
- # hostaddr
- 是IPv4
- 地址
- # service
- 是/etc/service
- 中的service name
- # port
- 是端口号
这个命令可以在不加任何参数的情况下直接运行,但是该命令一定需要用root账号来执行,因为lsof在运行时需要访问很多核心文件,需要的权限很高,其所输出的是目前系统中所有打开的文件,如图7-6所示。输出的字段有COMMAND、PID、USER、FD、TYPE、DEVICE、SIZE、NODE、NAME9列,这9个字段的意思如下:
·COMMAND:进程的名称。
·PID:进程标识符。
·USER:进程所有者。
·FD:文件描述符,应用程序通过文件描述符识别该文件。
·TYPE:文件类型,如DIR、REG等。
·DEVICE:磁盘的名称。
·SIZE:文件大小。
·NODE:索引节点。
·NAME:打开文件的全路径名称。
图7-6 lsof的输出
Linux系统中有很多日志文件会不断地被写入、更新,varlog/messages就是其中的一个。现在来看一下当前有什么进程正在使用该文件(syslogd是系统中负责写系统日志的进程)。
- [root@localhost ~]# lsof varlog/messages
- COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
- syslogd 2428 root 1w REG 253,0 109860 4161767 varlog/messages
在第4章中曾经将新创建的磁盘挂载到rootnewDisk下,现在假设要进入该目录,然后尝试将其umount卸载,系统提示device is busy,无法卸载。这时候使用lsof命令确认了一下,确实有进程在占用这个目录,于是通过cd命令找到家目录,然后再使用lsof确认,发现已经没有进程占用,这时候再umount就不会报错了。具体如下所示:
- [root@localhost ]# cd rootnewDisk/
- [root@localhost newDisk]# umount rootnewDisk/
- umount: rootnewDisk: device is busy
- umount: rootnewDisk: device is busy
- [root@localhost newDisk]# lsof rootnewDisk/
- COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
- bash 3310 root cwd DIR 8,17 4096 2 rootnewDisk/
- lsof 3971 root cwd DIR 8,17 4096 2 rootnewDisk/
- lsof 3972 root cwd DIR 8,17 4096 2 rootnewDisk/
- [root@localhost newDisk]# cd
- [root@localhost ]# lsof rootnewDisk/
- [root@localhost ~]# umount rootnewDisk/
使用lsof还可以查找使用了某个端口的进程,比如说如果系统中运行了sshd进程(基本上都是默认运行的),则该进程默认会绑定22端口,让我们来确认一下:
- [root@localhost ~]# lsof -i:22
- COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
- sshd 2815 root 3u IPv6 9402 TCP *:ssh (LISTEN)
如果你发现系统中打开了一些未知的端口,可以使用这个方法来确认具体是什么进程在使用。
使用lsof命令还有个更实用的功能,就是可以通过其恢复被删除的文件——但这是有条件的,必须是文件正在被某个进程使用,而且该进程未停止(也就是依然拥有打开文件的句柄)。我们知道,在Windows下恢复数据相对来说比较简单,因为Windows提供了回收站功能,删除的文件可以在其中简单地被找回。另外,Windows系统下的第三方软件也是非常丰富的,即使回收站被清空了,也有可能使用这些第三方软件协助恢复数据的软件。
现假设文件varlog/messages不小心被删除了,首先来确认一下当前是否有进程正在使用这个文件,如果有则可以继续,如果没有就无法使用该方法继续了。本例中看到有个PID为2449的进程正在使用该文件,那么接下来只要找到对应/proc目录下的文件就可以了。具体看以下的命令演示:
- [root@localhost ]# lsof | grep message
- syslogd 2449 root 1w REG 253,0 149423 4161767 varlog/messages
- [root@localhost ]# cat proc2449/fd/2 > varlog/messages
- [root@localhost ~]# Service syslogd restart