查找并删除打开但已被删除的大文件

查找并删除打开但已被删除的大文件

如何找到已删除但仍在应用程序中打开的大文件?即使某个进程打开了这样的文件,如何删除它?

情况是我们正在运行一个进程,该进程正在以惊人的速度填满日志文件。我知道原因,我可以解决它。在那之前,我想在不关闭进程的情况下 rm 或清空日志文件。

简单地执行rm output.log只会删除对该文件的引用,但它会继续占用磁盘上的空间,直到进程终止。更糟糕的是:在rming 之后,我现在无法找到文件在哪里或有多大!有没有办法找到该文件,并可能清空它,即使它仍然在另一个进程中打开?

我特指基于 Linux 的操作系统,例如 Debian 或 RHEL。

答案1

如果无法终止应用程序,可以截断而不是删除日志文件来回收空间。如果文件不是以追加模式(使用O_APPEND)打开的,那么下次应用程序写入该文件时,该文件将显示为与以前一样大(尽管前导部分稀疏并且看起来好像包含 NUL 字节),但空间将被回收(但这不适用于 Apple OS/X 上不支持稀疏文件的 HFS+ 文件系统)。

截断它:

: > /path/to/the/file.log

如果它已经被删除,在 Linux 上,您仍然可以通过执行以下操作来截断它:

: > "/proc/$pid/fd/$fd"

$pid打开文件的进程的进程 ID 以及它$fd在其下打开的一个文件描述符(您可以使用lsof -p "$pid".

如果您不知道 pid,并且正在查找已删除的文件,您可以执行以下操作:

lsof -nP | grep '(deleted)'

lsof -nP +L1,正如@user75021所述是一个更好的(更可靠、更便携的)选项(列出链接少于 1 个的文件)。

或者(在 Linux 上):

find /proc/*/fd -ls | grep  '(deleted)'

或者用以下命令找到大的zsh

ls -ld /proc/*/fd/*(-.LM+1l0)

如果应用程序是动态链接的,另一种方法是附加一个调试器并使其调用,close(fd)然后调用一个新的open("the-file", ....).

答案2

在此处查看快速入门:lsof快速开始

我很惊讶没有人提到 lsof 快速入门文件(包含在 lsof 中)。 “3.a”部分展示了如何查找打开的、未链接的文件:

lsof -a +L1 *mountpoint*

例如:

[root@enterprise ~]# lsof -a +L1 /tmp
COMMAND   PID   USER   FD   TYPE DEVICE    SIZE NLINK  NODE NAME
httpd    2357 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
mysqld   2588  mysql    4u   REG 253,17      52     0  1495 /tmp/ibY0cXCd (deleted)
mysqld   2588  mysql    5u   REG 253,17    1048     0  1496 /tmp/ibOrELhG (deleted)
mysqld   2588  mysql    6u   REG 253,17       0     0  1497 /tmp/ibmDFAW8 (deleted)
mysqld   2588  mysql    7u   REG 253,17       0     0 11387 /tmp/ib2CSACB (deleted)
mysqld   2588  mysql   11u   REG 253,17       0     0 11388 /tmp/ibQpoZ94 (deleted)
httpd    3457   root   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8437 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8438 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8439 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8440 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8441 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8442 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8443 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8444 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   16990 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   19595 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   27495 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   28142 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   31478 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)

答案3

实际上取决于文件系统驱动程序自由的分配的空间,通常只会发生一次全部引用该文件的文件描述符被释放。因此,除非您让应用程序关闭文件,否则您无法真正回收空间。这意味着要么终止它,要么在调试器中“稍微”使用它(例如关闭文件并确保它不会再次打开/写入,或者/dev/null改为打开)。或者你可以破解内核,但我建议不要这样做。

按照 Stephane 的建议截断文件可能会有所帮助,但真正的结果还取决于您的文件系统(例如,在任何情况下,只有在关闭文件后,预分配的块才可能被释放)。

这种行为背后的基本原理是,内核不知道如何处理针对此类文件的数据请求(读和写,但读实际上更关键)。

答案4

您可以使用以下命令清空该日志文件,而不是删除您现在无法终止的进程所保存的文件echo

echo -n > /var/log/myapp.log

您可以使用命令检查之后df- “已用字节”列将是减少

相关内容