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

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

只需执行rm output.log即可仅删除对该文件的引用,但它会继续占用磁盘空间,直到该进程终止。更糟:在rm ing之后,我现在无法找到文件的位置或大小!

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

评论

如果知道pid,则可以使用lsof -p 列出其打开的文件及其大小。删除的文件旁边会有一个(已删除)。删除的文件可能会链接到/ proc / / fd / 1。我不知道如何使进程在不终止的情况下停止写入其文件描述符。我认为这取决于过程。

谢谢。如何获得所有仍打开的rmed文件的PID?

@donothingsuccessfully lsof报告的“ deleted”标记是特定于Solaris的,实际上仅是Solaris 10或更高版本。 OP未指定他使用的操作系统。 @dotancohen在Solaris上,您可以通过管道传递lsof的输出来搜索已删除的内容,例如lsof | |。 grep“(已删除)”。当没有其他进程打开已删除文件时,内核将释放索引节点和磁盘块。进程没有“处理程序”,可以通过它们通知已从磁盘中删除了一个打开的,基本上是锁定的文件。

@ Johan,lsof | grep'(deleted)'也可以在Linux上使用。在Linux上,可以使用inotify机制(IN_DELETE_SELF事件)通知您文件删除(甚至在/ proc / some-pid / fd之外的任何目录中都没有任何条目的文件)

我创建了一个文件,并在VIM中将其打开,然后在另一个bash进程中对其进行了修剪。然后运行lsof | grep somefile并且它不在其中,即使该文件已在VIM中打开。

#1 楼

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

要截断它:

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


如果已将其删除,则在Linux上,您仍然可以通过以下方式截断它:

已打开文件的进程,并在其中打开了一个文件描述符(您可以使用$pid进行检查。可以做到:如@ user75021所述,
: > "/proc/$pid/fd/$fd"


$fd是一个更好的选项(更可靠,更可移植)(列出的文件少于1个链接)。

或(在Linux上):

lsof -nP | grep '(deleted)'


或者使用lsof -p "$pid"查找大的块:调试器使其调用lsof -nP +L1,然后调用新的zsh

评论


还有一个截断命令可以更明确地执行相同的操作。

–东武
13年3月20日在9:15

@dotancohen Stephane编辑为包含有关未知pid时如何执行此操作的信息。

–迪迪·科恩(Didi Kohen)
13年3月20日在10:48

@ OlivierDulac,lsof可能是最接近您可以列出打开文件的便携式解决方案的地方。在应用程序脚下关闭fd的调试器方法也应该很容易移植。

–StéphaneChazelas
13年3月20日在13:50

@StephaneChazelas:谢谢。我找到了一种列出所有在每个分区上打开文件的PID的方法:df -k | awk'NR> 1 {print $ NF}'| xargs fuser -Vud(然后轻松地向违规者发送信号以迫使他们释放fd)

–奥利维尔·杜拉克(Olivier Dulac)
13年3月20日在18:56



您也可以使用lsof + L1。在lsof手册页中:“格式为+ L1的规范将选择已取消链接的打开文件。格式为+ aL1 的规范将选择指定文件系统上的未链接的打开文件。”这应该比grepping更可靠。

–同步
14-10-23在6:26



#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)


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

br />
[root@enterprise ~]# locate -i quickstart |grep lsof
/usr/share/doc/lsof-4.78/00QUICKSTART


#3 楼

文件系统驱动程序实际上要释放分配的空间,通常只有在释放所有引用该文件的文件描述符后,才会发生这种情况。因此,除非您使应用程序关闭文件,否则您无法真正回收空间。这意味着要么终止它,要么在调试器中“稍微”播放它(例如,关闭文件并确保不再打开/写入该文件,或者打开/dev/null)。或者您可以破解内核,但是我建议您这样做。在任何情况下都可能仅在关闭文件后才释放)。

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

评论


由于Linux在大多数文件系统上都支持稀疏文件,因此行为是明确定义的,并且磁盘驱动程序可以真正释放磁盘空间。我已经对ext3和ext4进行了测试,它的工作方式就像Stephane所写的一样。

– jofel
13年3月20日在10:14

是什么让您说截断文件不会收回预分配的块?截断是为了释放数据,我认为这没有任何歧义。

–StéphaneChazelas
13年3月20日在11:22

文件系统可以保留分配的块以节省以后的时间(尤其是如果文件仍保持打开状态),尤其是在截断之前足够大的情况下。至少XFS似乎正在这样做。

–彼得
13年3月20日在12:53

谢谢彼得。我很高兴您解决本文中的“为什么”。

– dotancohen
13年3月21日在6:09

据我所知,截断打开的文件也确实会回收XFS上的空间。在Linux 4.9上同时测试了普通文件和使用fallocate分配的文件。您能否说明在什么文件系统和条件下截断文件不会回收空间?

–StéphaneChazelas
17年5月3日,11:52