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

dot*_*hen 142 process logs disk-usage open-files files

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

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

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

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

Sté*_*las 174

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

截断它:

: > /path/to/the/file.log
Run Code Online (Sandbox Code Playgroud)

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

: > "/proc/$pid/fd/$fd"
Run Code Online (Sandbox Code Playgroud)

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

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

lsof -nP | grep '(deleted)'
Run Code Online (Sandbox Code Playgroud)

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

或(在 Linux 上):

find /proc/*/fd -ls | grep  '(deleted)'
Run Code Online (Sandbox Code Playgroud)

或者找到大的zsh

ls -ld /proc/*/fd/*(-.LM+1l0)
Run Code Online (Sandbox Code Playgroud)

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

  • 你也可以使用`lsof +L1`。来自 lsof 手册页:“`+L1` 形式的规范将选择已取消链接的打开文件。`+aL1 <file_system>` 形式的规范将选择指定文件系统上未链接的打开文件。”。这应该比 grepping 更可靠一些。 (7认同)
  • 还有一个“截断”命令可以更明确地执行相同的操作。 (3认同)
  • @OlivierDulac,“lsof”可能是最接近可列出打开文件的便携式解决方案。关闭应用程序脚下的 fd 的调试器方法也应该非常便携。 (2认同)
  • @StephaneChazelas:谢谢。我找到了一种方法来列出在每个分区上打开一个文件的所有 PID:`df -k | awk 'NR>1 { 打印 $NF }' | xargs fuser -Vud`(然后很容易向违规者发送信号以迫使他们释放 fd) (2认同)

小智 42

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

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

lsof -a +L1 *mountpoint*
Run Code Online (Sandbox Code Playgroud)

例如:

[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)
Run Code Online (Sandbox Code Playgroud)

在 Red Hat 系统上查找快速启动文件的本地副本,我通常这样做:

[root@enterprise ~]# locate -i quickstart |grep lsof
/usr/share/doc/lsof-4.78/00QUICKSTART
Run Code Online (Sandbox Code Playgroud)

... 或这个:

[root@enterprise ~]# rpm -qd lsof
/usr/share/doc/lsof-4.78/00.README.FIRST
/usr/share/doc/lsof-4.78/00CREDITS
/usr/share/doc/lsof-4.78/00DCACHE
/usr/share/doc/lsof-4.78/00DIALECTS
/usr/share/doc/lsof-4.78/00DIST
/usr/share/doc/lsof-4.78/00FAQ
/usr/share/doc/lsof-4.78/00LSOF-L
/usr/share/doc/lsof-4.78/00MANIFEST
/usr/share/doc/lsof-4.78/00PORTING
/usr/share/doc/lsof-4.78/00QUICKSTART
/usr/share/doc/lsof-4.78/00README
/usr/share/doc/lsof-4.78/00TEST
/usr/share/doc/lsof-4.78/00XCONFIG
/usr/share/man/man8/lsof.8.gz
Run Code Online (Sandbox Code Playgroud)