这是“您应该知道的UNIX工具系列主题文章”的第三篇。在这篇文章里,我将介绍一个很有用的工具—lsof。如果说netcat是网络连接的瑞士军刀,那么我说lsof是UNIX调试的瑞士军刀。
Lsof严格遵循UNIX的哲学典范。它仅完成一项任务,并且做得极尽完美----它能够列出某个进程所打开的文件信息。打开的文件可以是普通文件、目录、NFS文件、块文件、字符文件、共享库、普通管道、命名管道、符号链接、socket流、网络socket、UNIX socket,等等等等。因为UNIX世界里,几乎所有东西都是文件,所以,您可以想像lsof的用处是多么的大。
您可以看看本主题系列的第一篇文章,关于 pipe viewer的介绍。如果您对这篇文章感兴趣,那么请订阅我的 rss feed。
怎样使用 lsof?
在这篇文章里,我会尽可能多地列举我能想到的用例,来说明lsof的用法。让我们从最简单的例子开始(或许您已经知道了),由浅入深地展开吧。
列出所有打开的文件
# lsof
不带任何参数执行lsof,就会列出所有进程打开的所有文件。
查找谁在使用某个文件
# lsof /path/to/file
以文件的路径为参数,lsof将会列出所有用这个文件的进程。
您也可以指定多个文件,lsof会列出所有使用这些文件的进程。
# lsof /path/to/file1 /path/to/file2
递归查找某个目录下所有打开的文件
# lsof +D /usr/lib
带上”+D”参数,lsof会在指定目录及其下所有子目录中查找找开的文件。注意这个操作效率比通常版本的grep低。
# lsof | grep '/usr/lib'
之所以慢,是因为”+D”首先查找所有文件,然后再执行输出。
列出某个用户打开的所有文件
# lsof -u pkrumins
“-u”选项(认为是user)限定输出内容,只显示”pkrumins”用户打开的文件。您也可以同时限定多个用户,用户名之间以逗号为分隔符(译者注:逗号左右不要出现空格):
# lsof -u rms,root
这条命令会列出rms用户和root用户打开的所有文件。
另一种方式是多次使用”-u”选项,也能达到相同的目的:
# lsof -u rms -u root
按进程名查找打开的文件
# lsof -c apache
“-c”选项限定只列出进程名以”apache”打头的进程所打开的文件。因此,可以不用写:
# lsof | grep foo
而写成更简短的版本:
# lsof -c foo
事实上,您可以仅指定进程名的开头部分进行查找:
# lsof -c apa
上面这条命令将列出所有名字以apa打头的进程所打开的文件。
您还可以同时指定多个”-c”选项,以关联多个进程:
# lsof -c apache -c python
这条命令将会列出apache和python打开的所有文件。
译者注,对于多线程的进程来说,显示TID(Task ID)有时是必要的,但是用“-c”选项缺省是不列出子任务的,这时可以加上"-K"(大写)选项。
列出某个用户或进程打开的所有文件
# lsof -u pkrumins -c apache
Lsof的选项可以关联组合。缺省的关联条件是或(OR)。这意味着上面这条命令输出的内容为:列出用户pkrumins 或进程apache打开的所有文件。
列出某个用户与某个进程打开的所有文件
# lsof -a -u pkrumins -c bash
注意”-a”选项。它把关联组合的逻辑,由或(OR)变成与(AND)。所以上面这条命令输出内容为:pkrumins用户所属的,bash进程打开的所有文件。
列出除了root用户之外,其它用户打开的所有文件
# lsof -u ^root
注意root用户名之前的”^”字符。它执行取反操作。所以这条命令输出所有非root用户打开的文件。
列出某个PID进程打开的所有文件
# lsof -p 1
“-p”(联想PID)选项,限定以进程的ID为过滤条件。记住,您可以在一个“-p”选项中,用逗号分隔的方式指定多个PID,也可以多次指定“-p”选项:
# lsof -p 450,980,333
这条命令列出PID为450、980和333的进程打开的所有文件。
列出某个PID之外,其它进程打开的所有文件
# lsof -p ^1
又碰到取反操作符”^”了。上面这条命令列出PID 1之外的进程打开的所有文件。
列出所有网络连接
# lsof -i
通过”-i”选项,lsof列出所有打开网络套接字(TCP和UDP)的进程。
列出所有TCP网络连接
# lsof -i tcp
”-i”选项有几个参数,”tcp”就是其中之一,它限定lsof仅显示打开TCP套接字的进程。
列出所有UDP网络连接
# lsof -i udp
”-i”选项的参数值改为”udp”,就可以显示打开UDP套接字的进程了。
查找谁占用了某个端口
# lsof -i :25
”-i”选项的参数值改为”:25”,lsof就会查找占用25端口的进程(包括TCP和UDP)。您也可能指定端口服务名(详见/etc/services)),而不指定具体端口号:
# lsof -i :smtp
查找谁占用了某个UDP端口
# lsof -i udp:53
同样,查找占用的TCP端口命令为:
# lsof -i tcp:80
查找某个用户占用的网络端口
# lsof -a -u hacker -i
这里,”-a”选项关联组合了”-u”和”-i”选项。上面使命列出了用户hacker所占用的网络端口。
列出所有NFS(网络文件系统)文件
# lsof -N
”-N”选项很容易记住,因为它就是NFS。
列出所有Unix socket文件
# lsof -U
”-U”选项很容易记住,因为它就是UNIX。
列出指定组ID的进程所打开的所有文件
# lsof -g 1234
进程组用于结进程进行逻辑分组。上面例子查找PGID为1234的进程组成员打开的所有文件。
列出与某个特定文件描述符关联的所有文件
# lsof -d 2
上面这条命令,列出所有打开文件描述符2的进程。您还可以指定文件描述符的范围:
# lsof -d 0-2
这样会列出与文件描述符0、1、2关联的所有进程。
“-d”还选项还有许多特定参数可选,比方说”mem”,它列出内存映射文件:
# lsof -d mem
还有”txt”表示加载进内存,正在执行的进程:
# lsof -d txt
输出占用某些资源的进程PID
# lsof -t -i
“-t”选项,限定lsof仅输出进程的PID。它与”-i”选项组合,就只显示所有打开网络连接的进程PID。这样,如果要杀死所有使用网络的进程就很容易了:
# kill -9 `lsof -t -i`
循环执行lsof
# lsof -r 1
“-r”选项,告诉lsof不断地重复执行。参数值1表示重复周期为1秒。这
# lsof -r 1 -u john -i -a
怎样安装lsof?
许多UNIX系统都预安装了lsof。如果您的系统没有,那么到source下载源码来安装。
BSD系统有一个叫fstat的工具,实现的类似的功能。
完整的文档在 man lsof可以找到,或者通过 lsof -h查看简单的帮助。
快来体验lsof的乐趣吧!