Linux 文件常用操作,文件句柄占用问题探究

linux   find   lsof  
发布于 Oct 19, 2024

在进行采集日志时,日志文件明明被滚动压缩并转移走了,但是发现磁盘空间还是在不断增长,统一目录下的总文件大小,发现与实际占用也不符,于是想到可能是文件句柄未释放导致的,本文就来记录一下文件及文件句柄查看相关的内容,方便查阅。

在 linux 中,一切皆文件,我们最熟悉的创建目录,创建文件,查看文件

mkdir test_dir
cd test_dir
touch test.log
ls -al

而对于文件来说,实际上是一个指向inode的链接, inode链接包含了文件的所有属性, 比如权限和所有者, 数据块地址(文件存储在磁盘的这些数据块中)。

当你删除(rm)一个文件时, 实际删除了指向inode的链接, 并没有删除inode的内容, 进程可能还在使用,只有当inode的所有链接完全删除后, 然后这些数据块才可以写入新的数据。

所谓的指向inode的链接,其实就是指 fd 文件描述符,我们来实际操作一下,理解一下上面的概念

查看文件 inode

如何查看文件的 inode 呢? ls 的 -i 参数可以查看文件的 inode 编号

ls -ali
total 8
1970254 drwxr-xr-x 2 root root 4096 Oct 18 16:03 .
2097155 drwx------ 1 root root 4096 Oct 18 16:03 ..
1970255 -rw-r--r-- 1 root root    0 Oct 18 16:03 test.log

其中第一列就是 inode 编号

我们在进行 mv 操作时,虽然文件名改变了,但是 inode 是不变的,你可以仅仅认为名称是一个软连接一样,文件本质不变

mv test test1.log
ls -ali

通过 inode 删除文件

通常情况下,我们直接使用 rm 命令就可以删除文件,但是如果遇到一些特殊字符(控制字符,乱码字符)之类的文件,键盘都打不出来,怎么办呢?这时候可以通过 find 配合 inode num 来删除文件。

find ./ -inum 1970255 -delete

文件句柄占用

终于来到了开头提到遇到的问题了,有时候我们发现了文件,但是空间并没有释放的问题,这个问题的原因就是文件句柄还在被进程占用导致的,我们来模拟一下。

touch a.log
echo aa > a.log
# 使用 tail 命令保持对 a.log 的监听
tail -f a.log

再打开一个终端窗口,删掉 a.log, 然后通过 lsof 命令查看文件句柄占用情况。

rm a.log
# 找到 tail 的进程号
ps -ef | grep tail
# 查看文件句柄的占用情况
lsof -p 7414

发现有一个 deleted 标识的 fd 占用,当前目录下已经没有 a.log 文件了,但是其实这个文件还没有释放。

查看进程打开的描述符,确实 tail 进程还占用着

# ls -al /proc/{进程ID}/fd/ 查看进程打开的 fd
ls -al /proc/7414/fd/

这时唯一的解决办法就是将 tail 进程关掉,这个文件才会被真正的删掉

ctrl + c 终止掉 tail 命令,再来查看

ls -al /proc/7414/fd/
lsof -p 7414

分享一个查看进程占用 fd 排行的小指令, 第一列表示 fd 打开数,第二列是进程ID

lsof -n | awk '{print $2}' | sort | uniq -c | sort -nr

文件恢复

这里的文件恢复是指 fd 还没释放,只是通过 rm 删掉的文件的恢复,其实也比较简单,将进程 fd 对应的文件再 copy 出来就可以了。

终端1的相关操作

终端2的相关操作

关键步骤就是标号 ④

cp /proc/7530/fd/3 aa.log

本次的分享到此结束,希望对你有所帮助。

如果你对我分享的内容感兴趣,欢迎扫码关注公众号:新质程序猿,并设置星标,推送更实时哟!

本文由 黄彦祥 创作,采用 知识共享署名 3.0 中国大陆许可协议 进行许可。
可自由转载、引用,但需署名作者且注明文章出处。