Shell 2_lsof命令用法详解

一、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 命令的区别

lsofnetstat 是两个在 Unix 和类 Unix 系统中常用的命令行工具,它们各自有不同的用途和特点:

  1. lsof 命令

用途

  • 列出系统上打开的文件,包括常规文件、目录、网络套接字、管道等。

特点

  • 显示打开文件的进程信息,包括进程ID、用户、状态等。
  • 可以显示文件被哪些进程使用,以及进程如何使用这些文件。
  • 可用于查找使用特定文件或目录的进程,或者查找占用特定端口的进程。
  1. netstat 命令

用途

  • 显示网络连接、路由表、接口统计等网络相关信息。

特点

  • 显示当前活动的网络连接,包括本地和远程地址、状态等。
  • 显示路由表,帮助了解数据包的路由路径。
  • 显示网络接口的状态,包括发送和接收的数据包数量等。
  1. 适用情况

使用 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. 列出特定文件的打开情况
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. 查找特定用户打开的文件
 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
  1. 查找特定进程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. 查看指定程序(进程)打开的文件
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. 查看指定目录下被打开的文件
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. 查找所有网络连接
 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. 查看特定端口的网络连接情况
 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 允许组合多个选项来精确定位所需的信息。例如:

  1. 查找用户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. 查看指定进程打开的网络连接
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. 查看指定状态的网络连接
 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 文件;