版本
# lsof -v
lsof version information:
revision: 4.93.2
latest revision: https://github.com/lsof-org/lsof
latest FAQ: https://github.com/lsof-org/lsof/blob/master/00FAQ
latest (non-formatted) man page: https://github.com/lsof-org/lsof/blob/master/Lsof.8
...
简介
lsof - list open files, 功能为列出所有打开的文件,看着似乎很平常的命令,但在Unix及衍生系统Everything is a file(descriptor)
一切皆文件的特征加持下,lsof命令也变的异常强大。
一个打开的文件也就可能是普通文件、目录、进程、符号链接、网络文件(如:网络socket、UNIX域socket、NFS文件)等。
# lsof -p 1 |head -n4
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root cwd DIR 252,5 4096 2 /
systemd 1 root rtd DIR 252,5 4096 2 /
systemd 1 root txt REG 252,5 1620224 7870624 /usr/lib/systemd/systemd
上面的输出中:
COMMAND: 命令名称,默认只显示前9个字符,可以使用+c w
进行修改, 例如: lsof +c 10
PID: 进程标识号
TID: 任务(线程)标识号,空白 TID 列表示一个进程
USER: 进程所属用户的用户ID号或登录名
FD: 文件描述符编号或描述,包括:
- cwd 当前工作目录
- err FD错误信息
- mem 内存映射文件
- mmap 内存映射设备
- pd 父目录
- rtd 根目录
- txt 程序文本(代码和数据)
- …
FD后跟以下字符描述打开文件的模式:
- r 读
- w 写
- u 读写
- - 未知
FD后跟以下字符描述文件的锁形式:
- r 部分文件读锁定
- R 整个文件读锁定
- w 部分文件写锁定
- W 整个文件写锁定
- u 任意长度的读写锁定
- U 未知类型
- …
TYPE: 与文件关联的节点的类型
- REG 普通文件
- DIR 目录
- IPv4 IPv4 socket
- IPv6 IPv6 socket
- inet Internet domain socket
- unix UNIX domain socket
- BLK 设备文件
- CHR 字符文件
- FIFO FIFO队列
- PIPE 管道
- LINK 链接文件
- …
DEVICE: 以逗号分隔的设备编号
SIZE, SIZE/OFF or OFFSET: 以bytes为单位的文件大小和/或偏移量。
NODE: 本地文件的节点号
NAME: 根据上述类型显示的确切名称
示例
列出所有打开的文件
lsof
列出某个进程打开的文件
lsof -p 1
列出某个用户打开的文件
lsof -u ubuntu
列出进程所有打开的IPv4网络文件
lsof -i 4 -a -p 1234
列出打开的IPv6网络文件
lsof -i 6
列出和端口相关的文件
lsof -i :22
lsof -i TCP:1-1024
禁止将网络号转换为主机名
使用-n参数在网络文件中禁止主机名转换,会更快
lsof -n
lsof -np 1
列出TCP或UDP连接
lsof -i TCP
lsof -i UDP
列出指定状态下监听的端口
lsof -i -s TCP:LISTEN
lsof -i -s TCP:ESTABLISHED
列出连接到某个主机的文件
lsof -i @192.168.10.10
lsof -i @192.168.10.10:22
列出某个命令打开的文件
lsof -c bash
查看哪些进程打开了文件
lsof /var/log/message
查看哪些进程打开了目录及目录下文件
lsof +d /var/log/
# 使用+D进行目录递归
lsof +D /var/log/
场景
关闭正在运行的连接
当我们会遇到想关闭某个连接又不想重启服务的时候,就可以用lsof查询后使用下面的方法关闭,这种方式也让我们更清晰的了解了文件描述符这种东西。
1.定位本地进程
ss -nplt
# ss or netstat
netstat -nplt
2.在进程中定位文件描述符
lsof -np $pid
找到连接的匹配文件描述符编号。它将类似于"97u",记录其中的97
3.连接进程
gdb -p $pid
4.关闭连接
// call close($fileDescriptor) //does not need ; at end.
// 示例
call close(97)
// 退出gdb
quit
恢复删除的文件
当我们碰到手抖误删了正在使用的文件时,可以先不要慌,使用lsof看一下是否还在占用。
# 查看文件是否被进程打开
ls -l /var/log/syslog
lsof /var/log/syslog
# 我们使用rm -f /var/log/syslog 模拟文件被删除
rm -f /var/log/syslog
1.查看文件是否还在占用
lsof -n |grep "/var/log/syslog"
# 可以看到类似以下的输出,后面的状态也变为了deleted
rsyslogd 302322 syslog 7w REG 252,5 349555 32244093 /var/log/syslog (deleted)
...
2.找到显示的PID和FD内容 根据前面输出的PID和FD进行定位,查看文件内容
# tail -f /proc/[PID]/fd/[FD]
tail -f /proc/302322/fd/7
3.执行恢复操作
# 恢复
cat /proc/302322/fd/7 > /var/log/syslog
# 权限修改
chown syslog:adm /var/log/syslog
# 重启占用进程
systemctl restart rsyslog