一、lsof 命令概述
1.1 lsof 命令概述
lsof(List Open Files)是一款在类Unix操作系统(如Linux、BSD和macOS)中使用的强大命令行工具。它用于列出当前系统上所有打开的文件。
由于在类Unix系统中,几乎所有东西都被当作文件来处理,lsof不仅可以显示常规文件,还可以显示网络套接字、管道、设备文件等。
lsof 允许用户对核心内存进行查看,以找出系统当前如何使用这些文件。lsof的简单用法可以告诉用户哪些进程打开了哪些文件,以及哪些文件由哪些进程打开。
lsof 查看的打开文件可以是:
- 普通文件
- 目录字符或块设备文件
- 共享库
- 管道、命名管道
- 符号链接
- 网络文件(如 NFS file、网络 socket,Unix 域名 socket)
- 其它类型的文件,等等
1.2 安装lsof
在大多数Linux发行版中,lsof通常默认安装。如果你的系统上未安装,可以使用以下包管理器进行安装:
1
2
3
4
5
|
# Debian/Ubuntu系统
sudo apt-get install lsof
# Red Hat/CentOS系统
sudo yum install lsof
|
1.3 lsof 命令和 netstat 命令的区别
lsof
和 netstat
是两个在 Unix 和类 Unix 系统中常用的命令行工具,它们各自有不同的用途和特点:
lsof
命令
用途:
- 列出系统上打开的文件,包括常规文件、目录、网络套接字、管道等。
特点:
- 显示打开文件的进程信息,包括进程ID、用户、状态等。
- 可以显示文件被哪些进程使用,以及进程如何使用这些文件。
- 可用于查找使用特定文件或目录的进程,或者查找占用特定端口的进程。
netstat
命令
用途:
特点:
- 显示当前活动的网络连接,包括本地和远程地址、状态等。
- 显示路由表,帮助了解数据包的路由路径。
- 显示网络接口的状态,包括发送和接收的数据包数量等。
- 适用情况
使用 lsof
的情况:
- 需要找出哪个进程打开了特定的文件或目录。
- 确定哪个进程占用了特定的端口,尤其是在端口冲突或服务无法启动时。
- 进行文件系统级别的监控或调试。
使用 netstat 的情况:
- 查看当前的网络连接状态,包括哪些服务正在监听或哪些连接是活跃的。
- 了解网络接口的状态,比如网络流量或错误统计。
- 查看或管理路由表,比如在网络故障排除时。
尽管 netstat
主要关注网络信息,而 lsof
更广泛地关注打开的文件,但在某些情况下,两者可以互换使用。例如,lsof
可以用来查看网络连接信息,尽管这可能不如 netstat
直观。同样,netstat
也可以显示一些文件描述符信息,但通常不如 lsof
全面。
1.4 输出格式
lsof
命令的输出包含多个字段,例如:
- COMMAND: 打开文件的命令名称
- PID: 进程ID
- USER: 用户名
- FD: 文件描述符
- TYPE: 文件类型(如REG、DIR、CHR、FIFO、SOCK等)
- DEVICE: 设备号
- SIZE/OFF: 文件大小或文件偏移
- NODE: 文件节点号
- NAME: 文件名或路径
可以使用管道和其他命令(如grep、awk)进一步处理lsof的输出。
示例:
1
2
3
4
5
6
7
8
9
10
11
|
[root@master1 ~]# lsof | head
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root cwd DIR 253,0 279 96 /
systemd 1 root rtd DIR 253,0 279 96 /
systemd 1 root txt REG 253,0 1632776 101375676 /usr/lib/systemd/systemd
systemd 1 root mem REG 253,0 20064 33655884 /usr/lib64/libuuid.so.1.3.0
systemd 1 root mem REG 253,0 265576 34174702 /usr/lib64/libblkid.so.1.1.0
systemd 1 root mem REG 253,0 90160 34758540 /usr/lib64/libz.so.1.2.7
systemd 1 root mem REG 253,0 157440 47422222 /usr/lib64/liblzma.so.5.2.2
systemd 1 root mem REG 253,0 23968 33655895 /usr/lib64/libcap-ng.so.0.0.0
systemd 1 root mem REG 253,0 19896 33656104 /usr/lib64/libattr.so.1.1.0
|
二、lsof 命令用法
2.1 lsof 命令的基本用法
运行 lsof
命令会列出所有当前系统上打开的文件,这通常会生成大量输出,因此需要使用一些选项参数来过滤和查找特定的信息。
- 列出特定文件的打开情况
1
2
3
4
5
6
7
|
lsof /path/to/file
# 示例:
[root@host ~]# lsof /var/log/messages
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
abrt-watc 845 root 4r REG 253,0 38173303 100871818 /var/log/messages
rsyslogd 1301 root 6w REG 253,0 38173303 100871818 /var/log/messages
|
- 查找特定用户打开的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
lsof -u username
# 示例
[root@host ~]# lsof -u macs
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 23586 macs cwd DIR 253,2 4096 99 /home/macs
bash 23586 macs rtd DIR 253,0 279 96 /
bash 23586 macs txt REG 253,0 964536 29046 /usr/bin/bash
bash 23586 macs mem REG 253,0 106172832 231929 /usr/lib/locale/locale-archive
bash 23586 macs mem REG 253,0 61560 35784956 /usr/lib64/libnss_files-2.17.so
bash 23586 macs mem REG 253,0 2156592 33655767 /usr/lib64/libc-2.17.so
bash 23586 macs mem REG 253,0 19248 35784944 /usr/lib64/libdl-2.17.so
bash 23586 macs mem REG 253,0 174576 33655848 /usr/lib64/libtinfo.so.5.9
bash 23586 macs mem REG 253,0 163312 36522418 /usr/lib64/ld-2.17.so
bash 23586 macs mem REG 253,0 123267 100958765 /usr/share/locale/zh_CN/LC_MESSAGES/bash.mo
bash 23586 macs mem REG 253,0 26970 67204748 /usr/lib64/gconv/gconv-modules.cache
bash 23586 macs 0u CHR 136,2 0t0 5 /dev/pts/2
bash 23586 macs 1u CHR 136,2 0t0 5 /dev/pts/2
bash 23586 macs 2u CHR 136,2 0t0 5 /dev/pts/2
bash 23586 macs 255u CHR 136,2 0t0 5 /dev/pts/2
|
- 查找特定进程ID (PID) 打开的文件
1
2
3
4
5
6
7
8
|
lsof -p PID
# 示例
[root@host ~]# lsof -p $(pgrep watchdogd)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
watchdogd 39 root cwd DIR 253,0 279 96 /
watchdogd 39 root rtd DIR 253,0 279 96 /
watchdogd 39 root txt unknown /proc/39/exe
|
- 查看指定程序(进程)打开的文件
1
2
3
4
5
6
7
8
|
lsof -c sshd
# 示例
[root@host ~]# lsof -c watchdogd
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
watchdogd 39 root cwd DIR 253,0 279 96 /
watchdogd 39 root rtd DIR 253,0 279 96 /
watchdogd 39 root txt unknown /proc/39/exe
|
- 查看指定目录下被打开的文件
1
2
3
4
5
6
7
8
9
|
lsof +D /home/ 或 lsof +d /home/
# 示例
[root@host ~]# lsof +D /etc/
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd-u 590 root mem REG 253,0 9011349 33554531 /etc/udev/hwdb.bin
systemd-u 590 root 6r REG 253,0 9011349 33554531 /etc/udev/hwdb.bin
avahi-dae 834 avahi cwd DIR 253,0 71 35969369 /etc/avahi
avahi-dae 834 avahi rtd DIR 253,0 71 35969369 /etc/avahi
|
参数说明:
+d
: 指定目录,不包括子目录
+D
: 指定目录,括子目录
- 查找所有网络连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
lsof -i
lsof -i@127.0.0.1 # 指定IP (网口)
# 示例
[root@host ~]# lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
rpcbind 825 rpc 6u IPv4 21347 0t0 UDP *:sunrpc
rpcbind 825 rpc 7u IPv4 21348 0t0 UDP *:puparp
rpcbind 825 rpc 8u IPv4 21349 0t0 TCP *:sunrpc (LISTEN)
rpcbind 825 rpc 9u IPv6 21350 0t0 UDP *:sunrpc
rpcbind 825 rpc 10u IPv6 21351 0t0 UDP *:puparp
rpcbind 825 rpc 11u IPv6 21352 0t0 TCP *:sunrpc (LISTEN)
avahi-dae 834 avahi 12u IPv4 20251 0t0 UDP *:mdns
avahi-dae 834 avahi 13u IPv4 20252 0t0 UDP *:39385
chronyd 843 chrony 5u IPv4 21790 0t0 UDP localhost:323
chronyd 843 chrony 6u IPv6 21791 0t0 UDP localhost:323
dhclient 1101 root 5u IPv6 24279 0t0 UDP master1:dhcpv6-client
cupsd 1289 root 10u IPv6 25487 0t0 TCP localhost:ipp (LISTEN)
cupsd 1289 root 11u IPv4 25488 0t0 TCP localhost:ipp (LISTEN)
sshd 1291 root 3u IPv4 25394 0t0 TCP *:ssh (LISTEN)
sshd 1291 root 4u IPv6 25396 0t0 TCP *:ssh (LISTEN)
|
通过 -i
参数查看网络连接的情况,包括连接的ip、端口等;以及一些服务的连接情况,例如:sshd等。也可以通过指定ip查看该ip的网络连接情况。
- 查看特定端口的网络连接情况
1
2
3
4
5
6
7
8
9
10
11
|
lsof -i :port
# 示例:
[root@host ~]# lsof -i :22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1291 root 3u IPv4 25394 0t0 TCP *:ssh (LISTEN)
sshd 1291 root 4u IPv6 25396 0t0 TCP *:ssh (LISTEN)
frpc 1293 root 8u IPv4 117350010 0t0 TCP localhost:filenet-re->localhost:ssh (ESTABLISHED)
frpc 1293 root 10u IPv4 117275347 0t0 TCP localhost:59472->localhost:ssh (ESTABLISHED)
frpc 1293 root 11u IPv4 117351547 0t0 TCP localhost:filenet-peior->localhost:ssh (ESTABLISHED)
frpc 1293 root 14u IPv4 117275773 0t0 TCP localhost:59438->localhost:ssh (ESTABLISHED)
|
2.2 lsof 命令的高级组合选项用法
lsof
允许组合多个选项来精确定位所需的信息。例如:
- 查找用户root打开的所有网络连接
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@host ~]# lsof -a -u root -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dhclient 1101 root 5u IPv6 24279 0t0 UDP master1:dhcpv6-client
cupsd 1289 root 10u IPv6 25487 0t0 TCP localhost:ipp (LISTEN)
cupsd 1289 root 11u IPv4 25488 0t0 TCP localhost:ipp (LISTEN)
sshd 1291 root 3u IPv4 25394 0t0 TCP *:ssh (LISTEN)
sshd 1291 root 4u IPv6 25396 0t0 TCP *:ssh (LISTEN)
frpc 1293 root 7u IPv4 108115543 0t0 TCP master1:46025->134.175.85.172:afs3-fileserver (ESTABLISHED)
frpc 1293 root 10u IPv4 117275347 0t0 TCP localhost:59472->localhost:ssh (ESTABLISHED)
frpc 1293 root 11u IPv4 117447382 0t0 TCP localhost:35222->localhost:ssh (ESTABLISHED)
frpc 1293 root 12u IPv4 117447508 0t0 TCP localhost:35228->localhost:ssh (ESTABLISHED)
frpc 1293 root 13u IPv4 117223985 0t0 TCP localhost:58168->localhost:ssh (ESTABLISHED)
...
|
- 查看指定进程打开的网络连接
1
2
3
4
5
6
7
|
lsof -i -a -p PID
# 示例
[root@host ~]# lsof -i -a -p $(pgrep sshd | head -n 1)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1291 root 3u IPv4 25394 0t0 TCP *:ssh (LISTEN)
sshd 1291 root 4u IPv6 25396 0t0 TCP *:ssh (LISTEN)
|
参数解释:
- -i: 查看网络连接情况,
- -a: 查看存在的进程,
- -p: 指定进程PID。
- 查看指定状态的网络连接
1
2
3
4
5
6
7
8
9
10
11
12
|
[root@host ~]# lsof -n -P -i TCP -s TCP:ESTABLISHED
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
frpc 1293 root 7u IPv4 108115543 0t0 TCP 192.168.0.201:46025->134.175.85.172:7000 (ESTABLISHED)
frpc 1293 root 8u IPv4 117539786 0t0 TCP 127.0.0.1:36516->127.0.0.1:22 (ESTABLISHED)
frpc 1293 root 9u IPv4 117544965 0t0 TCP 127.0.0.1:36528->127.0.0.1:22 (ESTABLISHED)
frpc 1293 root 10u IPv4 117275347 0t0 TCP 127.0.0.1:59472->127.0.0.1:22 (ESTABLISHED)
frpc 1293 root 13u IPv4 117223985 0t0 TCP 127.0.0.1:58168->127.0.0.1:22 (ESTABLISHED)
sshd 20002 root 3u IPv4 117216124 0t0 TCP 127.0.0.1:22->127.0.0.1:58168 (ESTABLISHED)
sshd 20002 root 9u IPv4 117216209 0t0 TCP 127.0.0.1:43648->127.0.0.1:41056 (ESTABLISHED)
code-f1a4 20054 root 12u IPv4 117224081 0t0 TCP 127.0.0.1:41056->127.0.0.1:43648 (ESTABLISHED)
sshd 22492 root 3u IPv4 117273720 0t0 TCP 127.0.0.1:22->127.0.0.1:59438 (ESTABLISHED)
sshd 22496 root 3u IPv4 117273751 0t0 TCP 127.0.0.1:22->127.0.0.1:59442 (ESTABLISHED)
|
参数解释:
- -n: no host names,
- -P: no port names,
- -i:TCP指定协议,
- -s:指定协议状态;
通过多个参数我们可以清晰的查看网络连接情况、协议连接情况等。
三、lsof 高阶用法
3.1 借助 lsof 命令恢复被删除文件
在Linux系统中删除了一个文件,只要进程还在对文件进行操作,就可能还存在一个inode的引用:/proc/进程号/fd/文件描述符,只要知道当前打开文件的进程pid和文件描述符fd,即可利用lsof命令还原出被删除的文件。
遇到这种情况,不要关闭或者重启服务器系统,也不要关闭或重启相关服务或者进程,如:恢复apache的访问日志/var/log/httpd/access_log时,不能关闭或者重启服务器系统,也不能重启httpd服务。
通过 lsof 命令可恢复这类被删除的文件, 操作示例:
Step 1:启动进程打开文件
1
2
3
4
5
6
7
8
9
10
11
|
[root@host ~]# tail -f test.sh
# 根据规划 hosts 设置主机名
grep $(ifconfig eth1 |awk 'NR==2{print $2}') /etc/hosts | awk '{print $2}' | xargs hostnamectl set-hostname
grep master1 /etc/hosts | sed 's/master1/cluster.lermubei.org/' >> /etc/hosts
#
# # 将桥接的IPv4流量传递到iptables的链
# cat > /etc/sysctl.d/k8s.conf << EOF
# net.bridge.bridge-nf-call-ip6tables = 1
# net.bridge.bridge-nf-call-iptables = 1
# EOF
# sysctl --system # 生效
|
Step 2: 另外一个 shell 中删除 被 tail 打开的文件
1
|
[root@host ~]# rm -rf test.sh
|
Step 3: 使用 lsof 命令找回被删除的文件
首先通过 lsof 命令找到打开 test.sh 文件的进程的 PID 和 test.sh 文件的FD(文件描述符);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[root@host ~]# lsof | grep test.sh
tail 3813 root 3r REG 253,0 498 100871843 /root/test.sh (deleted)
[root@host ~]# cat /proc/3813/fd/3
#!/bin/bash
# 添加hosts
cat ./cluster_hosts.txt >> /etc/hosts
# 根据规划 hosts 设置主机名
grep $(ifconfig eth1 |awk 'NR==2{print $2}') /etc/hosts | awk '{print $2}' | xargs hostnamectl set-hostname
grep master1 /etc/hosts | sed 's/master1/cluster.lermubei.org/' >> /etc/hosts
#
# # 将桥接的IPv4流量传递到iptables的链
# cat > /etc/sysctl.d/k8s.conf << EOF
# net.bridge.bridge-nf-call-ip6tables = 1
# net.bridge.bridge-nf-call-iptables = 1
# EOF
# sysctl --system # 生效
|
从上面命令输出可以看到,这个打开 /root/test.sh 文件的进程的PID是3813,文件 /root/test.sh 的FD(文件描述符)是3,状态为deleted,标记被删除,但其实该文件并没有从磁盘中删除。
如果删除的文件还存在操作的进程,数据将可能被找回,可以在 /proc/3813/fd/3 找到被删除的 /root/test.sh 文件;