7.5 查询进程打开的文件:lsof

lsof(list open files)是一个列出当前系统中所有打开文件的工具。早在第1章中就提到过,Linux中一切皆文件,所以在系统中,被打开的文件可以是普通文件、目录、网络文件系统中的文件、字符设备、管道、socket等。那么如何知晓现在系统打开的是哪些文件呢,这时lsof命令就有用武之地了。不过,这个命令在系统中可能并未默认安装,在CentOS下如果可以联网,简单输入yum install lsof-y即可安装该工具,如果是在RedHat下,则需要到原始安装光盘中寻找lsof的rpm包进行安装。关于如何安装软件包,将在后一章中详细描述。该命令的使用方法如下:


  1. [root@localhost ~]# lsof
  2. options
  3. filename
  4. #
  5. 常用的参数列表
  6. #lsof filename
  7. 显示打开指定文件的所有进程
  8. #lsof -c string
  9. 显示COMMAND
  10. 列中包含指定字符的进程所有打开的文件
  11. #lsof -u username
  12. 显示所属于user
  13. 进程打开的文件
  14. #lsof -g gid
  15. 显示归属于gid
  16. 的进程情况
  17. #lsof +d DIR
  18. 显示目录下被进程打开的文件
  19. #lsof +D DIR
  20. 同上,但是会搜索目录下的所有目录,时间相对较长
  21. #lsof -d FD
  22. 显示指定文件描述符的进程
  23. #lsof -n
  24. 不将IP
  25. 转换为hostname
  26. ,默认是不加-n
  27. 参数
  28. #lsof -i
  29. 用以显示符合条件的进程情况
  30. #lsof -i[46] [protocol][@hostname|hostaddr][:service|port]
  31. # 46
  32. IPv4
  33. IPv6
  34. # protocol
  35. TCP
  36. UDP
  37. # hostname
  38. 指主机名
  39. # hostaddr
  40. IPv4
  41. 地址
  42. # service
  43. 是/etc/service
  44. 中的service name
  45. # port
  46. 是端口号

这个命令可以在不加任何参数的情况下直接运行,但是该命令一定需要用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.5 查询进程打开的文件:lsof - 图1

图7-6 lsof的输出

Linux系统中有很多日志文件会不断地被写入、更新,varlog/messages就是其中的一个。现在来看一下当前有什么进程正在使用该文件(syslogd是系统中负责写系统日志的进程)。


  1. [root@localhost ~]# lsof varlog/messages
  2. COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
  3. syslogd 2428 root 1w REG 253,0 109860 4161767 varlog/messages

在第4章中曾经将新创建的磁盘挂载到rootnewDisk下,现在假设要进入该目录,然后尝试将其umount卸载,系统提示device is busy,无法卸载。这时候使用lsof命令确认了一下,确实有进程在占用这个目录,于是通过cd命令找到家目录,然后再使用lsof确认,发现已经没有进程占用,这时候再umount就不会报错了。具体如下所示:


  1. [root@localhost ]# cd rootnewDisk/
  2. [root@localhost newDisk]# umount rootnewDisk/
  3. umount: rootnewDisk: device is busy
  4. umount: rootnewDisk: device is busy
  5. [root@localhost newDisk]# lsof rootnewDisk/
  6. COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
  7. bash 3310 root cwd DIR 8,17 4096 2 rootnewDisk/
  8. lsof 3971 root cwd DIR 8,17 4096 2 rootnewDisk/
  9. lsof 3972 root cwd DIR 8,17 4096 2 rootnewDisk/
  10. [root@localhost newDisk]# cd
  11. [root@localhost ]# lsof rootnewDisk/
  12. [root@localhost ~]# umount rootnewDisk/

使用lsof还可以查找使用了某个端口的进程,比如说如果系统中运行了sshd进程(基本上都是默认运行的),则该进程默认会绑定22端口,让我们来确认一下:


  1. [root@localhost ~]# lsof -i:22
  2. COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
  3. sshd 2815 root 3u IPv6 9402 TCP *:ssh (LISTEN)

如果你发现系统中打开了一些未知的端口,可以使用这个方法来确认具体是什么进程在使用。

使用lsof命令还有个更实用的功能,就是可以通过其恢复被删除的文件——但这是有条件的,必须是文件正在被某个进程使用,而且该进程未停止(也就是依然拥有打开文件的句柄)。我们知道,在Windows下恢复数据相对来说比较简单,因为Windows提供了回收站功能,删除的文件可以在其中简单地被找回。另外,Windows系统下的第三方软件也是非常丰富的,即使回收站被清空了,也有可能使用这些第三方软件协助恢复数据的软件。

现假设文件varlog/messages不小心被删除了,首先来确认一下当前是否有进程正在使用这个文件,如果有则可以继续,如果没有就无法使用该方法继续了。本例中看到有个PID为2449的进程正在使用该文件,那么接下来只要找到对应/proc目录下的文件就可以了。具体看以下的命令演示:


  1. [root@localhost ]# lsof | grep message
  2. syslogd 2449 root 1w REG 253,0 149423 4161767 varlog/messages
  3. [root@localhost ]# cat proc2449/fd/2 > varlog/messages
  4. [root@localhost ~]# Service syslogd restart