Linux 命令之 lsof -- 列出当前系统已打开的文件列表

文章目录

命令介绍
常用选项
字段说明
文件类型
文件描述符
文件状态模式
锁模式
参考示例
(一)查看打开指定文件的所有进程
(二)列出由某个 PID 对应的进程打开的所有文件
(三)查看指定名称的进程所打开的文件列表
(四)列出除了某个用户以外的被打开的文件列表
(五)列出除了某个进程之外,其它进程打开的文件列表
(六)列出所有的网络连接
(七)列出所有的 TCP 网络连接
(八)列出所有的 UDP 网络连接
(九)查看有哪些进程在使用指定的端口
(十)查看哪些进程在使用指定的 UDP 端口
(十一)查看哪些进程在使用指定的 TCP 端口
(十二)列出某个用户所有活跃的网络端口
(十三)查看指定用户组所打开的文件列表
(十四)根据文件描述符的范围查看有关的文件列表
(十五)哪些进程在使用 apache 的可执行文件
(十六)查看连接到某个远程主机端口的进程
(十七)不断查看远程主机 ftp 连接的情况
(十八)递归查找某个目录中所有打开的文件
(十九)列出某个用户打开的所有文件
(二十)列出由某个用户或某个进程打开的所有文件
(二十一)查看某个用户的所有网络连接
(二十二)列出所有内存映射文件
(二十三)列出所有加载在内存中并正在执行的进程
(二十四)查看使用网络资源的进程 pid
(二十五)杀掉所有使用网络的进程
(二十六)循环列出文件
(二十七)查看被打开的和网络相关的文件
(二十八)统计系统打开的文件总数
(二十九)杀掉属于某个用户的打开了文件的所有进程
(三十)列出某个 IP 的网络连接信息
(三十一)同时列出连接某主机多个端口的网络连接文件
经典场景应用
(一)查看指定进程打开的特定文件(查看日志文件路径)
(二)查看文件的内存映射路径(查看已删除文件的内容)
(三)恢复被删除的文件
(四) 日志文件删除后磁盘空间可用空间没有变大,怎么解决
命令介绍

lsof 是 List Opened Files 的缩写,该命令是用于列出当前系统打开的文件的工具,也就是查看被进程打开的文件的工具,且可以用来找回或恢复被删除的文件。

在 Linux 下“一切皆文件”,任何事物都以文件的形式存在,包括但不限于 pipes, sockets, directories, devices等。通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件,例如:传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字等。

lsof 是一个 Linux 下的非常实用和方便的系统级的监控、诊断工具。因为 lsof 命令需要访问核心内存和各种文件,所以必须以 root 用户的身份运行它才能够充分地发挥其功能。

系统在后台为每个应用程序分配了一个文件描述符(程序打开文件,系统都会分配一个文件描述符给该程序),该文件描述符为应用程序与基础操作系统之间的交互提供了通用接口。因为应用程序打开文件的描述符列表提供了大量关于这个应用程序本身的信息,因此通过 lsof 工具查看这个列表,对系统监测以及排错将是很有帮助的。

在 lsof 显示的结果中,每行显示一个打开的文件,若不指定条件默认显示所有进程打开的所有文件。

常用选项

选项 说明
-a 指示多个选项之间为 与 的关系,必须都满足时才显示结果
-c<进程名> 列出指定进程所打开的文件
-g 显示归属于 GID 的进程情况
-d<文件号> 列出占用该文件号的进程,文件号就是文件描述符。例如:显示使用fd为4的进程
+d<目录> 列出指定目录下被打开的文件
+D<目录> 递归列出指定目录下被打开的文件
-n<目录> 列出使用NFS的文件
-n 不解析主机名 ,不将 IP 转换为 Host Name,缺省是不加上 -n 选项,疑问??
-i<条件> 列出符合条件的且与网络相关的进程。(4、6、协议、:端口、 @ip )不加条件默认列出所有的网络连接。
-p<进程号> 列出指定进程号所打开的文件
-P 不解析端口号
-N 列出所有NFS(网络文件系统)文件
-u<用户名> 列出指定用户打开的文件, 该选项可以指定用户名 或 user ID,可以通过逗号分隔多个用户名称或 user ID,也可以通过符号 ^ 对条件取反
-U 列出所有UNIX域Socket文件
-t 只输出 PID
-h 显示帮助信息
-v 显示版本信息
字段说明

字段名称 说明
COMMAND 进程的名称,默认以 9 个字符长度显示的命令名称。可使用 +c 参数指定显示的宽度,若 +c 后跟的参数为零,则显示命令的全名。这个 +c 参数好像无效
PID 进程标识符
PPID 父进程标识符,父进程的IP号,默认不显示,当使用 -R 参数可打开。
USER 进程所有者,命令的执行 UID 或系统中登陆的用户名称。默认显示为用户名,当使用 -l 参数时,可显示 UID。
PGID 进程所属组标识符,进程组的ID 编号,默认也不会显示,当使用 -g 参数时可打开。
FD File Descriptor Number,文件描述符,应用程序通过文件描述符识别文件,例如:cwd、txt 等
TYPE 文件类型,例如: DIR、REG 等
DEVICE 指定磁盘的名称,以逗号分隔设备编号,使用character special、block special表示的设备号
SIZE 文件的大小,如果不能用大小表示的,会留空。使用-s参数控制。
NODE 索引节点(文件在磁盘上的标识),本地文件的node码,或者协议,如TCP等
NAME 打开文件的确切名称,挂载点和文件的全路径(链接会被解析为实际路径),或者连接双方的地址和端口、状态等
文件类型

英文标识 说明
REG 普通文件
DIR 表示目录
CHR 表示字符类型
BLK 块设备类型
UNIX UNIX 域套接字,UNIX Domain Sockets
FIFO 先进先出 (FIFO) 队列
IPv4/IPv6 网际协议 (IP) 套接字,IPv4/IPv6 套接字
LINK 链接文件
文件描述符

描述符 说明
cwd Current Work Director 的缩写,应用程序的当前工作目录,这是该应用程序启动的目录,除非它本身对这个目录进行更改
txt 该类型的文件是程序代码,表示程序的可执行文件
lnn library references (AIX)
er FD information error (see NAME column)
jld jail directory (FreeBSD)
ltx shared library text (code and data)
mxx hex memory-mapped type number xx
m86 DOS Merge mapped file
mem memory-mapped file,表示内存映射文件
mmap memory-mapped device
pd parent directory
rtd root directory,表示根目录
tr kernel trace file (OpenBSD)
v86 VP/ix mapped file
0 表示标准输出
1 表示标准输入
2 表示标准错误
文件状态模式

一般在标准输出、标准错误、标准输入后还跟着文件状态模式。

文件状态模式 说明
u 表示该文件被打开并处于读取/写入模式,例如:10u,10 是打开该文件时返回的一个整数,表示文件号是10,u 表示该文件被打开且处于读取/写入模式
r 表示该文件被打开并处于只读模式
w 表示该文件被打开并处于只写模式
space 表示该文件的状态模式为 unknow,且没有锁定
- 表示该文件的状态模式为 unknow,且被锁定
锁模式

在文件状态模式后面,还跟着相关的锁:

锁模式 说明
N for a Solaris NFS lock of unknown type
r for read lock on part of the file
R for a read lock on the entire file
w for a write lock on part of the file(文件的部分写锁)
W for a write lock on the entire file(整个文件的写锁)。表示该应用程序拥有对整个文件的写锁(表示该进程拥有对文件写操作的锁),该文件描述符用于确保每次只能打开一个应用程序实例。初始打开每个应用程序时,都具有三个文件描述符,从 0 到 2,分别表示标准输入、标准输出和标准错误。所以大多数应用程序所打开的文件的 FD 都是从 3 开始。
u for a read and write lock of any length
U for a lock of unknown type
x for an SCO OpenServer Xenix lock on part of the file
X for an SCO OpenServer Xenix lock on the entire file
space if there is no lock。表示该文件的状态模式为 unknow,且没有锁定。
- 表示该文件的状态模式为 unknow,且被锁定。
参考示例

(一)查看打开指定文件的所有进程

查看哪些进程正在使用文件 /var/log/mysqld.log:
[root@htlwk0001host ~]# lsof /var/log/mysqld.log
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 1064381 mysql 1w REG 253,1 3240699 935706 /var/log/mysqld.log
mysqld 1064381 mysql 2w REG 253,1 3240699 935706 /var/log/mysqld.log
1
2
3
4
哪些进程在占用文件 /etc/passwd:
[root@htlwk0001host ~]# lsof /etc/passwd
1
哪些进程在占用 hda6:
[root@htlwk0001host ~]# lsof /dev/hda6
1
哪些进程在占用光驱:
[root@htlwk0001host ~]# lsof /dev/cdrom
1
(二)列出由某个 PID 对应的进程打开的所有文件

查看 PID 为 1064381 的进程所打开的全部文件列表:

[root@htlwk0001host ~]# lsof -p 1064381
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 1064381 mysql cwd DIR 253,1 4096 636744 /var/lib/mysql
mysqld 1064381 mysql rtd DIR 253,1 244 128 /
mysqld 1064381 mysql txt REG 253,1 251816000 51228705 /usr/sbin/mysqld
mysqld 1064381 mysql mem REG 253,1 553480 50342901 /usr/lib64/libpcre2-8.so.0.7.1
mysqld 1064381 mysql mem REG 253,1 304848 50342907 /usr/lib64/libselinux.so.1
1
2
3
4
5
6
7
(三)查看指定名称的进程所打开的文件列表

查看进程 mysqld 所打开的全部文件列表:

[root@htlwk0001host ~]# lsof -c mysqld
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 1064381 mysql cwd DIR 253,1 4096 636744 /var/lib/mysql
mysqld 1064381 mysql rtd DIR 253,1 244 128 /
mysqld 1064381 mysql txt REG 253,1 251816000 51228705 /usr/sbin/mysqld
mysqld 1064381 mysql mem REG 253,1 553480 50342901 /usr/lib64/libpcre2-8.so.0.7.1
mysqld 1064381 mysql mem REG 253,1 304848 50342907 /usr/lib64/libselinux.so.1
mysqld 1064381 mysql mem REG 253,1 33224 50343274 /usr/lib64/libuuid.so.1.3.0

-c 选项限定只列出以 mysqld 开头的进程打开的文件:

你同样可以制定多个 -c 参数:

[root@htlwk0001host ~]# lsof -c apache -c python
1
这会列出所有由 apache 和 python 打开的文件。

(四)列出除了某个用户以外的被打开的文件列表

[root@htlwk0001host ~]# lsof -u ^root
COMMAND PID TID TASKCMD USER FD TYPE DEVICE SIZE/OFF NODE NAME
polkitd 715 polkitd cwd DIR 253,1 244 128 /
polkitd 715 polkitd rtd DIR 253,1 244 128 /

说明:^ 符号,表示 取反 的意思。

(五)列出除了某个进程之外,其它进程打开的文件列表

[root@htlwk0001host ~]# lsof -p ^1234
1
(六)列出所有的网络连接

列出所有打开了网络套接字(TCP和UDP)的进程:

[root@htlwk0001host ~]# lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
chronyd 743 chrony 5u IPv4 20334 0t0 UDP localhost:323
chronyd 743 chrony 6u IPv6 20335 0t0 UDP localhost:323
NetworkMa 901 root 24u IPv4 22817 0t0 UDP htlwk0001host:bootpc->_gateway:bootps
systemd-r 955 systemd-resolve 12u IPv4 23063 0t0 UDP *:hostmon
systemd-r 955 systemd-resolve 13u IPv4 23064 0t0 TCP *:hostmon (LISTEN)
1
2
3
4
5
6
7
(七)列出所有的 TCP 网络连接

[root@htlwk0001host ~]# lsof -i tcp
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd-r 955 systemd-resolve 13u IPv4 23064 0t0 TCP *:hostmon (LISTEN)
systemd-r 955 systemd-resolve 15u IPv6 23067 0t0 TCP *:hostmon (LISTEN)
nginx 26556 root 8u IPv4 137518 0t0 TCP *:http (LISTEN)
nginx 26556 root 9u IPv4 137519 0t0 TCP *:https (LISTEN)
nginx 26556 root 10u IPv6 137520 0t0 TCP *:https (LISTEN)
nginx 26556 root 11u IPv6 137521 0t0 TCP *:http (LISTEN)
svnserve 34295 root 3u IPv4 182743 0t0 TCP *:svn (LISTEN)
httpd 34871 root 4u IPv6 186113 0t0 TCP *:tproxy (LISTEN)

tcp 选项会强制 lsof 只列出打开 TCP sockets 的进程。

(八)列出所有的 UDP 网络连接

[root@htlwk0001host ~]# lsof -i udp
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
chronyd 743 chrony 5u IPv4 20334 0t0 UDP localhost:323
chronyd 743 chrony 6u IPv6 20335 0t0 UDP localhost:323
NetworkMa 901 root 24u IPv4 22817 0t0 UDP htlwk0001host:bootpc->_gateway:bootps
systemd-r 955 systemd-resolve 12u IPv4 23063 0t0 UDP *:hostmon
systemd-r 955 systemd-resolve 14u IPv6 23066 0t0 UDP *:hostmon
systemd-r 955 systemd-resolve 18u IPv4 23069 0t0 UDP 127.0.0.53:domain

(九)查看有哪些进程在使用指定的端口

让 lsof 列出占用 TCP 或 UDP 的 3306 端口的进程:

[root@htlwk0001host ~]# lsof -i:3306
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 1050299 root 72u IPv6 19427946 0t0 TCP htlwk0001host:60664->47.114.59.224:mysql (ESTABLISHED)
java 1050299 root 78u IPv6 19427982 0t0 TCP htlwk0001host:60704->47.114.59.224:mysql (ESTABLISHED)
java 1050299 root 79u IPv6 19427963 0t0 TCP htlwk0001host:60684->47.114.59.224:mysql (ESTABLISHED)
java 1050299 root 80u IPv6 19427972 0t0 TCP htlwk0001host:60696->47.114.59.224:mysql (ESTABLISHED)

你也可以使用 /etc/services 中制定的端口名称来代替端口号,比如:

[root@htlwk0001host ~]# lsof -i :smtp
1
(十)查看哪些进程在使用指定的 UDP 端口

[root@htlwk0001host ~]# lsof -i udp:55
1
(十一)查看哪些进程在使用指定的 TCP 端口

[root@htlwk0001host ~]# lsof -i tcp:55
1
(十二)列出某个用户所有活跃的网络端口

[root@htlwk0001host ~]# lsof -a -u test -i
1
(十三)查看指定用户组所打开的文件列表

查找所有 PGID 为 5555 的进程打开的文件:

[root@htlwk0001host ~]# lsof -g 5555;
1
(十四)根据文件描述符的范围查看有关的文件列表

显示使用 fd 为 2-3 的进程:
[root@htlwk0001host ~]# lsof -d 2-3
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 2u CHR 1,3 0t0 6597 /dev/null
systemd 1 root 3w CHR 1,11 0t0 6603 /dev/kmsg
1
2
3
4
上面的命令会列出所有描述符为 2 或 3 的文件。

显示使用 fd 为 4 的进程:
[root@htlwk0001host ~]# lsof -d 4
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 4u a_inode 0,14 0 9454 [eventpoll]
systemd-j 560 root 4u unix 0xffff944b07050480 0t0 11200 /run/systemd/journal/socket type=DGRAM
systemd-u 587 root 4u netlink 0t0 17814 KOBJECT_UEVENT
auditd 673 root 4u unix 0xffff944b2d4e8d80 0t0 380481 type=STREAM
1
2
3
4
5
6
上面这个命令会列出所有以描述符 4 打开的文件。

(十五)哪些进程在使用 apache 的可执行文件

[root@htlwk0001host ~]# lsof `which httpd`
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
httpd 34871 root txt REG 253,1 580064 53187782 /usr/sbin/httpd
httpd 1048930 apache txt REG 253,1 580064 53187782 /usr/sbin/httpd
httpd 1048931 apache txt REG 253,1 580064 53187782 /usr/sbin/httpd
httpd 1049032 apache txt REG 253,1 580064 53187782 /usr/sbin/httpd
httpd 1049033 apache txt REG 253,1 580064 53187782 /usr/sbin/httpd
httpd 1049411 apache txt REG 253,1 580064 53187782 /usr/sbin/httpd

(十六)查看连接到某个远程主机端口的进程

哪些进程打开了到 www.dpqyw.com 的UDP 端口 8088(ntp) 的连接:
[root@htlwk0001host ~]# lsof -i UDP@www.dpqyw.com:8088
1
哪些进程打开了到 192.168.2.245 TCP 端口 1521 的连接:
[root@svr-db-test ~]# lsof -i tcp@192.168.2.245:1521 -n
1
lsof -n 不将IP转换为hostname,缺省是不加上-n参数。

(十七)不断查看远程主机 ftp 连接的情况

[root@htlwk0001host ~]# lsof -i tcp@www.dpqyw.com:ftp -r -n
=======
=======
=======
1
2
3
4
说明:

-r,lsof 会永远不断的执行,直到收到中断信号
+r,lsof 会一直执行,直到没有档案被显示,缺省是 15s 刷新
-n 不将 IP 转换为 hostname,缺省是不加上 -n 参数
(十八)递归查找某个目录中所有打开的文件

[root@htlwk0001host ~]# lsof +D /usr/lib
1
加上+D 参数,lsof 会对指定目录进行递归查找,注意这个参数要比 grep 版本慢:

[root@htlwk0001host ~]# lsof | grep '/usr/lib'
1
之所以慢是因为+D首先查找所有的文件,然后一次性输出。

(十九)列出某个用户打开的所有文件

[root@htlwk0001host ~]# lsof -u liaowenxiong
1
-u 选项限定只列出所有被用户 liaowenxiong 打开的文件,你可以通过逗号指定多个用户:

[root@htlwk0001host ~]# lsof -u liaowenxiong,liudehua
1
这条命令会列出 liaowenxiong 和 liudehua 用户打开的所有文件。

你也可以像下面这样使用多个 -u 做同样的事情:

[root@htlwk0001host ~]# lsof -u liaowenxiong -u root
1
(二十)列出由某个用户或某个进程打开的所有文件

[root@htlwk0001host ~]# lsof -u pkrumins -c apache
1
你可以组合使用多个选项,这些选项默认进行 或 关联,也就是说上面的命令会输出由用户 pkrumins 或者进程 apache 打开的文件,若希望多个选项之间是 与 关联,可用加上选项 -a。

(二十一)查看某个用户的所有网络连接

查看用户 root 的所有网络连接:

[root@htlwk0001host ~]# lsof -a -u root -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
NetworkMa 901 root 24u IPv4 22817 0t0 UDP htlwk0001host:bootpc->_gateway:bootps
nginx 26556 root 8u IPv4 137518 0t0 TCP *:http (LISTEN)
nginx 26556 root 9u IPv4 137519 0t0 TCP *:https (LISTEN)
nginx 26556 root 10u IPv6 137520 0t0 TCP *:https (LISTEN)
1
2
3
4
5
6
使用 -a 将 -u 和 -i 选项组合可以让 lsof 列出某个用户的所有网络行为。

(二十二)列出所有内存映射文件

[root@htlwk0001host ~]# lsof -d mem
1
(二十三)列出所有加载在内存中并正在执行的进程

[root@htlwk0001host ~]# lsof -d txt
1
(二十四)查看使用网络资源的进程 pid

[root@htlwk0001host ~]# lsof -t -i
1
-t 选项输出进程的 PID,你可以将它和 -i 选项组合输出使用某个端口的进程的 PID,如下:

[root@htlwk0001host ~]# lsof -t -i:3306
1050299
1050398
1064381
1
2
3
4
(二十五)杀掉所有使用网络的进程

[root@htlwk0001host ~]# kill -9 'lsof -t -i'
1
(二十六)循环列出文件

[root@htlwk0001host ~]# lsof -r 1
1
-r 选项让 lsof 可以循环列出文件直到被中断,参数1 就是循环间隔时间是 1 秒,即循环周期是 1 秒,意思是每秒钟重复打印一次,这个选项最好同某个范围比较小的查询组合使用,比如用来监测用户的网络活动:

[root@htlwk0001host ~]# lsof -r 1 -u john -i -a
1
(二十七)查看被打开的和网络相关的文件

使用 -i 选项用来查看网络相关的文件,其参数的格式如下:

lsof -i [46][protocol][@hostname|hostaddr][:service|port]
1
说明:

46 表示 IP 协议的版本
protocol 表示网络协议的名称,比如 TCP 或 UDP
hostname 或 hostaddr 表示主机域名或者主机 IP 地址
service 指 /etc/services 中的端口名称,比如:smtp
port 表示端口号,可以指定一个或多个
-i 选项默认会同时输出 IPv4 和 IPv6 打开的文件。

只列出 IPv4 或 IPv6 打开的文件:
[root@htlwk0001host ~]# lsof -i 4
[root@htlwk0001host ~]# lsof -i 6
1
2
列出占用一定端口范围的所有的进程:
[root@htlwk0001host ~]#lsof -i TCP:1-1024
1
(二十八)统计系统打开的文件总数

[root@htlwk0001host ~]# lsof -P -n | wc -l
69360
1
2
命令中的 -P 选项表示不解析端口号,-n 选项表示不解析主机名,这两个选项主要的目的是为了提升 lsof 命令的执行速度。wc -l 命令则用来统计 lsof 命令输出的行数。

(二十九)杀掉属于某个用户的打开了文件的所有进程

[root@htlwk0001host ~]# kill -9 `lsof -t -u nick`
1
[root@htlwk0001host ~]# kill -9 $(lsof -t -u nick)
1
(三十)列出某个 IP 的网络连接信息

[root@htlwk0001host ~]# lsof -i @47.114.59.256
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 1050299 root 72u IPv6 19473546 0t0 TCP htlwk0001host:36448->47.114.59.224:mysql (ESTABLISHED)
java 1050299 root 78u IPv6 19472650 0t0 TCP htlwk0001host:36488->47.114.59.224:mysql (ESTABLISHED)
java 1050299 root 79u IPv6 19473549 0t0 TCP htlwk0001host:36450->47.114.59.224:mysql (ESTABLISHED)
1
2
3
4
5
(三十一)同时列出连接某主机多个端口的网络连接文件

列出目前连接主机 hadoop 的端口为:20,21,22,25,53,80 的所有文件信息,且每隔3秒不断的执行 lsof 指令:

[root@htlwk0001host ~]# lsof -i @hadoop:20,21,22,25,53,80 -r 3
1
经典场景应用

(一)查看指定进程打开的特定文件(查看日志文件路径)

场景描述:

同事今天请假了,但负责的 webserver 服务出现了问题,老板让你看一下 webserver 服务的日志,但你不知道 webserver 服务的日志文件路径,配置文件太复杂你不太懂,这时你可以执行以下命令查看日志文件路径。
[devl@xungen ~]$ lsof -c webserver | grep -e 'log$'
webserver 10124 devl 4u REG 253,1 8814787 109523 /home/devl/application/webserver/log/webserver.00.log
1
2
(二)查看文件的内存映射路径(查看已删除文件的内容)

场景描述:

新来的同事误删除了 webserver 服务的日志文件,现在线上环境出现问题,需要查看 webserver 的日志,老板让紧急处理一下,这时你只能通过日志文件的内存映射路径来查看日志内容,那么怎么获取文件的内存映射路径呢?你要记住内存映射路径的固定格式:/proc/进程ID/fd/句柄。接着你要知道 webserver 进程 ID 和日志文件的句柄,那么这时我们就可以使用命令 lsof,来查看进程ID和文件句柄了。
注意:文件句柄又叫文件描述符又叫文件号

[devl@xungen ~]$ lsof -c webserver | grep -e 'log$'
webserver 10124 devl 4u REG 253,1 8814787 109523 /home/devl/application/webserver/log/webserver.00.log
1
2
以上的执行结果显示 webserver 服务的进程 ID 为 10124,日志文件句柄为 4u(即 4 号句柄),所以 /proc/10124/fd/4 就是日志文件(webserver.00.log)在 webserver 进程中的内存映射路径,这时你用 tail 命令就可查看日志文件了。

[devl@xungen ~]$ tail -f /proc/10124/fd/4
[20190602 09:51:04|INF] start route ping process success
[20190602 09:51:04|INF] ping host[127.0.0.1:8888][3951] success
[20190602 09:51:09|INF] check session success
[20190602 09:51:09|INF] start route ping process success
[20190602 09:51:09|INF] ping host[127.0.0.1:8888][3596] success
[20190602 09:51:14|INF] start route ping process success
[20190602 09:51:14|INF] ping host[127.0.0.1:8888][3390] success
[20190602 09:51:19|INF] start route ping process success
[20190602 09:51:19|INF] ping host[127.0.0.1:8888][3383] success
[20190602 09:51:19|INF] check session success

扩展知识:

当进程打开了某个文件时,只要该进程保持打开该文件,即使将其删除,它依然存在于磁盘中。这意味着,进程并不知道文件已经被删除,它仍然可以向打开该文件时提供给它的文件描述符进行读取和写入。除了该进程之外,这个文件是不可见的,因为已经删除了其相应的目录索引节点。 在 /proc 目录下存储着反映内核和进程树的各种文件。/proc 目录挂载的是在内存中所映射的一块区域,所以这些文件和目录并不存在于磁盘中,因此当我们对这些文件进行读取和写入时,实际上是从内存中获取相关信息。大多数与 lsof 相关的信息都存储于以进程 ID 命名的目录中,例如: /proc/1234 中存储的是 PID 为 1234 的进程的信息。每个进程目录中存储着各种文件,它们可以使得应用程序简单地了解进程的内存空间、文件描述符列表、指向磁盘上的文件的符号链接和其他系统信息。
(三)恢复被删除的文件

当系统中的某个文件被意外地删除了,只要这个时候系统中还有进程正在访问该文件,那么我们就可以通过 lsof 从 /proc 目录下恢复该文件的内容。 假如,由于误操作将 /var/log/messages 文件删除掉了,那么这时要将 /var/log/messages 文件恢复的方法如下:

首先使用 lsof 来查看当前是否有进程打开 /var/logmessages 文件,如下:

[root@htlwk0001host ~]# lsof |grep /var/log/messages
syslogd 1283 root 2w REG 3,3 5381017 1773647 /var/log/messages (deleted)
1
2
从上面的信息可以看到进程 syslogd(PID=1283)打开文件的文件描述符为 2w。同时还可以看到 /var/log/messages 已经标记被删除了。因此我们可以在 /proc/1283/fd/2 中查看相应的信息,如下:

[root@htlwk0001host ~]# head -n 10 /proc/1283/fd/2
Aug 4 13:50:15 holmes86 syslogd 1.4.1: restart.
Aug 4 13:50:15 holmes86 kernel: klogd 1.4.1, log source = /proc/kmsg started.
Aug 4 13:50:15 holmes86 kernel: Linux version 2.6.22.1-8 (root@everestbuilder.linux-ren.org) (gcc version 4.2.0)
1 SMP Wed Jul 18 11:18:32 EDT 2007
Aug 4 13:50:15 holmes86 kernel: BIOS-provided physical RAM map:
Aug 4 13:50:15 holmes86 kernel: BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
Aug 4 13:50:15 holmes86 kernel: BIOS-e820: 000000000009f000 - 00000000000a0000 (reserved)
Aug 4 13:50:15 holmes86 kernel: BIOS-e820: 0000000000100000 - 000000001f7d3800 (usable)
Aug 4 13:50:15 holmes86 kernel: BIOS-e820: 000000001f7d3800 - 0000000020000000 (reserved)
Aug 4 13:50:15 holmes86 kernel: BIOS-e820: 00000000e0000000 - 00000000f0007000 (reserved)
Aug 4 13:50:15 holmes86 kernel: BIOS-e820: 00000000f0008000 - 00000000f000c000 (reserved)

如果可以通过文件描述符查看相应的数据,那么就可以使用 I/O 重定向将其复制到文件中,命令语句如下:

[root@htlwk0001host ~]# cat /proc/1283/fd/2 > /var/log/messages
1
或者

[root@htlwk0001host ~]# sh -c 'cat /proc/1283/fd/2 > /var/log/messages'
1
然后修复文件的权限属性并重启 rsyslog 服务:

[root@htlwk0001host ~]# chown messages:adm /var/log/messages
[root@htlwk0001host ~]# systemctl restart rsyslog.service
1
2
这样就完成了 /var/log/messages 文件的恢复工作。对于许多应用程序,尤其是日志文件和数据库,这种恢复删除文件的方法非常有用。

(四) 日志文件删除后磁盘空间可用空间没有变大,怎么解决

发现文件系统 /tmp 目录下空间居然用满了,但用 du 命令统计 /tmp 目录中所有文件的大小,发现并没有大文件,怎么回事呢?出现这样的情况,很有可能是被删除的大文件依旧有其它程序在使用,所以依旧占用着磁盘空间,只是我们正常的方式无法查看到此文件,换句话说就是文件没有被彻底删除,这时候我们可以使用命令 lsof 求证下 。

步骤 1:查看系统磁盘的使用情况

[root@htlwk0001host ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 8.6G 1.5G 6.7G 18% /
/dev/sda10 784G 325G 420G 44% /u01
/dev/sda5 8.7G 7.9G 407M 96% /tmp
/dev/sda2 15G 2.8G 11G 21% /usr
/dev/sda1 122M 12M 104M 10% /boot
tmpfs 7.9G 4.0K 7.9G 1% /dev/shm
1
2
3
4
5
6
7
8
如上所示,/tmp 可用空剩下 407M。

步骤 2:使用命令 lsof 查看正在被进程使用的与 /tmp 相关的文件

[root@htlwk0001host ~]# sudo lsof | grep /tmp
sleep 18833 peien.htg 1w REG 8,5 8321143673 54 /tmp/netstat.log (deleted)
netstat_2 13571 peien.htg 1w REG 8,5 8321143673 54 /tmp/netstat.log (deleted)
tcprstat 18823 root 2w REG 8,5 43632 49 /tmp/myrt.daemon.log
sh 18822 mysql 2w REG 8,5 43632 49 /tmp/myrt.daemon.log
sh 18822 mysql 1w REG 8,5 43632 49 /tmp/myrt.daemon.log
myrt.pl 26045 mysql 2w REG 8,5 43632 49 /tmp/myrt.daemon.log
myrt.pl 26045 mysql 1w REG 8,5 43632 49 /tmp/myrt.daemon.log
check_age 25298 mysql 2w REG 8,5 22049 33 /tmp/check_agent.log
check_age 25298 mysql 1w REG 8,5 22049 33 /tmp/check_agent.log
mysqld 3784 mysql 6u REG 8,5 15156 13 /tmp/ibH3IFN9 (deleted)

如上所示列表中的第二行,文件大小7个多G,文件标记已删,但是依旧被进程“netstat_2”占用,该进程的 PID=13571。

步骤 3: 我们可以使用命令 ps 查看进程更为详细的信息

[root@htlwk0001host ~]# ps -ef | grep 13571
51717 13571 1 0 2011 ? 00:15:00 /bin/bash /tmp/netstat_20110829.sh
51717 21456 13571 0 09:40 ? 00:00:00 sleep 10
zhuxu 21458 17014 0 09:40 pts/0 00:00:00 grep 13571
1
2
3
4
步骤 4:接着我们将此进程 kill 掉

[root@htlwk0001host ~]# sudo kill -9 13571
1
步骤 5:然后我们再看看那个已删的文件是否被进程占用着

[root@htlwk0001host ~]# sudo lsof | grep /tmp
tcprstat 22084 root 2w REG 8,5 49339 49 /tmp/myrt.daemon.log
sh 22083 mysql 2w REG 8,5 49339 49 /tmp/myrt.daemon.log
sh 22083 mysql 1w REG 8,5 49339 49 /tmp/myrt.daemon.log
myrt.pl 26045 mysql 2w REG 8,5 49339 49 /tmp/myrt.daemon.log
myrt.pl 26045 mysql 1w REG 8,5 49339 49 /tmp/myrt.daemon.log
check_age 25298 mysql 2w REG 8,5 24583 33 /tmp/check_agent.log
check_age 25298 mysql 1w REG 8,5 24583 33 /tmp/check_agent.log
mysqld 3784 mysql 6u REG 8,5 15156 13 /tmp/ibH3IFN9 (deleted)
su 17013 root cwd DIR 8,5 4096 2 /tmp
sort 22090 zhuxu cwd DIR 8,5 4096 2 /tmp

如上所示结果,看不到那个已删的大文件了。

步骤 6:我们再看看系统磁盘分区的使用情况,确认下 /tmp 的使用空间是否增加了

[root@htlwk0001host ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 8.6G 1.5G 6.7G 18% /
/dev/sda10 784G 325G 420G 44% /u01
/dev/sda5 8.7G 56M 8.2G 1% /tmp
/dev/sda2 15G 2.8G 11G 21% /usr
/dev/sda1 122M 12M 104M 10% /boot
tmpfs 7.9G 4.0K 7.9G 1% /dev/shm

如上所示,目录 /tmp 的可用空间变成 8.2G 了。
————————————————
版权声明:本文为CSDN博主「liaowenxiong」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liaowenxiong/article/details/116002282

posted @ 2022-04-07 19:52  专注it  阅读(1594)  评论(0编辑  收藏  举报