磁盘空间不足:我该如何找出占用了空间的文件?

我在运行16.04的其中一台服务器上遇到了问题:磁盘空间已经用尽。

我不知道是什么占用了这些空间。有没有一个命令可以列出当前目录的大小,这样我就可以遍历并找到占用所有空间的目录了?


2检查磁盘使用分析器。 - Pranal Narayan
1@PranalNarayan 很抱歉,由于它在我的服务器上,所以没有图形用户界面(GUI)。 - Karl Morrison
1真讨厌,现在我去找了一下,发现了这个https://bugs.launchpad.net/ubuntu/+source/baobab/+bug/942255,真希望它是真的存在的。 - Sam
1关于"没有图形界面,只是一个服务器"的问题:你可以安装图形界面应用程序(假设你对它和支持库在服务器上运行满意),然后通过X11隧道传输SSH,在本地屏幕上使用它,类似这样export DISPLAY=:0.0; ssh -Y <user>@<server> filelight(将filelight替换为你喜欢的工具)。当然,如果绝对没有剩余空间,如果你还没有安装该工具,你需要使用其他工具! - David Spillett
11@DavidSpillett 如上所述,服务器上已经没有剩余空间了。因此我无法安装任何东西。 - Karl Morrison
@KarlMorrison 正如我在那条评论中所说的一样。但是我指出,如果服务器确实具备工具和库,作为一个没有直接GUI访问权限的服务器,并不意味着不能使用它们。即使服务器不是本地的,通过SSH进行X远程连接对于许多工具来说效果很好(尽管某些工具在高延迟链路上的响应可能不太理想,所以取决于你和服务器之间的远近程度以及所使用的工具,结果可能会有所不同)。 - David Spillett
即使你没有空间,也可以删除一些不必要的东西并安装一个工具。 - Viktor Mellgren
@ViktorMellgren 如果服务器上有垃圾文件,那确实是个问题。不过我的服务器上几乎没有垃圾文件,所以这种情况才变成了问题。不过你说得对,在大多数情况下可以删除一些东西 :) - Karl Morrison
@KarlMorrison 介意分享一下它是什么吗?:D - user595510
@MarkYisri 当然可以!该命令将我带到了Docker存储其镜像的目录。我有一个脚本正在创建镜像,当构建时会出现悬空的镜像https://www.projectatomic.io/blog/2015/07/what-are-docker-none-none-images/。这导致它们只是*存在*,因为我的脚本删除了某个标签。在cronjob上运行此操作,直到所有空间被占满,就会开始使用无图像:) - Karl Morrison
尝试在根目录上执行此命令,然后逐级进入您想要的目录:du -sh * | sort -h - Dnyaneshwar Harer
13个回答

像往常一样,在Linux中,有多种方法可以完成工作。但是,如果您需要通过命令行界面(CLI)完成它,这是我首选的方法:

我首先以root或使用sudo来运行以下命令:

du -cha --max-depth=1 / | grep -E "M|G"

grep的作用是将返回的行限制在以兆字节或千兆字节为单位的值范围内。如果您的磁盘足够大,还可以添加|T来包括以太字节的数量。由于/proc、/sys和/ dev不是真正的磁盘文件,所以可能会出现一些错误。但是,它仍然应该为根目录中的其余目录提供有效的输出。找到最大的目录后,您可以在其中运行命令,以缩小问题的范围。例如,如果/var是最大的目录,您可以像下面这样操作:
du -cha --max-depth=1 /var | grep -E "M|G"

这应该会引导你找到问题儿童!

额外考虑事项

虽然上述命令肯定能解决问题,但下面的评论中有一些建设性的批评指出了你还可以包括一些其他内容。

我提供的grep命令可能会导致偶尔返回带有大写G或M的目录或文件的“K”值。如果您绝对不希望出现任何带有K值的目录,您需要提升正则表达式的创造性和复杂性。例如:grep -E "^[0-9\.]*[MG]" 如果您知道哪个驱动器存在问题,并且它上面还挂载了其他驱动器,您不想浪费时间在搜索中包括它们,您可以在du命令中添加-x标志。该标志的手册描述如下:
-x, --one-file-system 跳过不同文件系统的目录
您可以对du命令的输出进行排序,使最高值位于底部。只需将以下内容附加到命令的末尾:| sort -h

2这正是我所做的。 - Lightness Races in Orbit
5你的grep命令会返回任何名称中包含字母M或G的文件夹,一个有创意的正则表达式应该匹配带有可选的点+M|G的数字,也许是"^[0-9]*[.]*[0-9]*[MG]" - Xen2050
4如果你知道问题出在哪个驱动器上,你可以使用-x选项让du只针对那个驱动器进行扫描(在命令行中提供)。你还可以通过管道传递给sort -h来正确排序以兆字节/千兆字节为单位的可读值。通常我会省略--max-depth选项,直接搜索整个驱动器,然后根据需要进行适当排序,将最大的文件显示在底部。 - Muzer
@Muzer,为什么要用-x来搞这个?只需将驱动器的挂载点作为参数传递给du命令即可。 - alexis
1@alexis 我的经验是,有时候我会在我感兴趣的挂载点下面发现其他垃圾(尤其是如果那是/),使用-x可以确保我不会错误计算东西。如果你的/已经满了,而你又有一个单独挂载的/home或其他目录,使用-x几乎是必要的,以摆脱无关的东西。所以我发现一直使用它更容易,以防万一。 - Muzer
好观点,我没有特别考虑过斜线(/)... - alexis
非常感谢大家的建议。:) @Xen2050 一个更有创意/复杂的正则表达式可以排除我不想包含在输出中的文件夹。然而,我没有包含的唯一其他输出是那些具有K数量数据的目录。如果出现一个这样的目录,对用户来说真的没有影响。而且记住一个简单和短的正则表达式比记住一个长的要容易得多(也更快写)。但是,如果你正在编写脚本并且确实不能让K值出现,那么你的方法会更好。 - TopHat
@Muzer 你提出了一些关于如何进一步细分和组织磁盘使用情况的好观点,我会考虑在我的回答中提及它们。至于移除--max-depth,我还不确定是否完全同意。这样做会强迫你等待系统计算整个系统上每个目录的磁盘使用情况。这会增加很多额外的开销,而你只需自己查看哪个目录要遍历一次最大深度,而无需深入其他目录。 - TopHat
@TopHat 它不是已经为每个目录计算磁盘使用量了吗?还是我误解了?由于Linux中不存储目录大小,因此必须计算它是否要求du显示它。唯一的计算方法是将每个文件和子目录的大小相加,而计算这些大小的唯一方法是将这些大小相加等等。 - Muzer
@Muzer在遍历所有内容时,它必须分别重新计算每个目录和文件的值,以便获得每个目录和文件的正确总数。对于具有最大深度的一个目录,它只需要执行一次计算。这就是为什么如果您不添加最大深度,返回结果的时间会显著延长。 - TopHat
你可能想在find命令的选项中添加-xdev。 这样可以阻止它跨越到其他已挂载的分区。 - CSM
1如果你有排序,就不需要使用grep。 - OrangeDog
你可以简单地使用 du -cha /*/,而不是 du -cha --max-depth=1 / - phuclv
这个命令让我的机器花了45年的时间才完成。 - Trevor Hickey
如果你使用sort -hr命令,它会先显示较大的结果,如果你更喜欢这样的话。我也是先进行排序,然后再进行grep操作,这样仍然可以突出显示“G”或“M”。 - JohnRDOrazio

你可以使用ncdu来完成这个任务。它的效果非常好。
sudo apt install ncdu

enter image description here


60我真是自己踢了一脚,因为通常我都会用这个程序,但是由于没有剩余空间,我无法安装它哈哈。 - Karl Morrison
1@KarlMorrison 我看到了几种可能的解决方案,只需将其通过sshfs挂载到另一台计算机上,并在那里运行ncdu(假设你已经在该计算机上安装了ssh服务器..)- 或者如果你没有在该计算机上安装ssh服务器,你可以反过来,在另一台服务器上安装ncdu并通过sshfs挂载它,然后从挂载点运行ncdu(假设你已经在服务器上安装了sshfs)- 或者如果两者都没有... 如果ncdu是一个单独的脚本,你可以使用curl http://path/to/ncdu | sh命令,它将在内存中运行,并使用IO stdin缓存,但这需要一些运气。可能还有一种方法可以创建一个RAM磁盘。 - hanshenrik
@KarlMorrison 或者你可以启动一个Linux的实时映像,并在其中安装它。 - user595510
3安装完成后,在命令行中输入sudo ncdu /。使用sudo是因为如果不加sudo,它将无法报告由root拥有的文件夹的大小,而输入/是因为如果不输入这个,它只会从你所在的文件夹递归地报告下去。 - Max Carroll
1ncdu是Ubuntu用户必备的工具。 - Ciasto piekarz
这个东西简直太棒了 - uzaysan
非常感谢!就是这样! - nlavr
如上所述,ncdu 支持一个 -x 标志,你可能希望传递该标志以排除 / 下的其他已挂载文件系统。 - dimo414

我使用这个命令:
sudo du -aBM -d 1 . | sort -nr | head -20

有时候,我需要从根目录/运行它,因为我把一些东西放在了一个奇怪的位置。

给你一个加一的赞,因为它有效!然而,TopHats的解决方案实际上读取我的驱动器更快! - Karl Morrison
我通常发现在不使用-d 1开关的情况下更有用(通常是使用less而不是head -20),这样我就可以得到一个完整的递归列出的按照它们消耗的空间排序的文件和目录列表。这样,如果我看到一个占用很多空间的目录,我可以向下滚动查看是否大部分空间实际上被其中某个特定文件或子目录占用。这是找到一些不需要的文件和目录以便释放一些空间的好方法:只需向下滚动,直到您看到您确定不想保留的内容,然后删除它并重复此操作。 - Ilmari Karonen
@KarlMorrison 它并不是更快地读取,只是 sort 在开始输出之前等待输出完成。 - muru
@muru 啊,好的。不过我更希望能够更快地获取信息,这样我就可以更快地开始遍历了,如果这个说法更好的话! - Karl Morrison

已经有很多关于如何找出占用大部分空间的目录的好答案了。如果你有理由相信只有少数几个大文件是主要问题,而不是许多小文件,你可以使用类似以下的方法:

find / -size +10M

如果你也对不使用命令感兴趣的话,这里有一个应用程序:Filelight

它可以让你快速可视化任何文件夹中占用磁盘空间的内容。

enter image description here


1这是我通过SSH登录的服务器,没有图形界面。 - Karl Morrison
@KarlMorrison 我觉得有办法通过ssh运行图形界面程序,但这是一个以后的想法,当你有空间安装软件包时再考虑。 - Xen2050
@David 哦,是的,我正在努力摆脱那个。在我之前使用的另一个平台上,这是必要的。我会修正那条评论的。 - user595510
@Karl 是的,如果客户端已经安装了X,那么很容易:ssh -X <你的主机>,然后从命令行运行你的程序。 - user595510
@MarkYisri 重点是你需要安装该程序及其依赖项。而Filelight这个案例至少需要KDElibs和Qt,它们并不小。请参考此页面上的filelight Ubuntu软件包,注意它有多少个依赖项。 - Ruslan
这是最好的工具。非常方便,完全符合要求..!! - Samitha Chathuranga

我不了解Ubuntu,也无法检查我的答案,但是根据我以前作为Unix管理员的经验,在这里发布我的答案。
  1. 找出哪个文件系统的空间不足

    df -h
    

    将列出所有文件系统,它们的大小和可用空间。如果你调查有足够空间的文件系统,那么你只是浪费时间。假设满的文件系统是/myfilesystem。检查df输出是否有挂载在/myfilesystem子目录下的文件系统。如果有的话,下面的步骤必须针对这种情况进行调整。

  2. 找出该文件系统中文件占用了多少空间

    du -sh /myfilesystem
    

    可以使用-x选项来确保只计算属于该文件系统的文件。某些Unix变体(例如Solaris)不支持du的-x选项。那么你需要使用一些解决方法来找到你的文件系统的du。

  3. 现在检查可见文件的du是否大致等于df显示的已用空间大小。如果是这样,你可以开始查找/myfilesystem文件系统中的大文件/目录进行清理。

  4. 要查找目录/.../dir的最大子目录,请使用以下命令

    du -sk /.../dir/*|sort -n
    

    -k选项强制du以千字节为单位输出大小,没有任何单位。这可能是某些系统的默认设置。然后你可以省略此选项。最大的文件/子目录将显示在输出的底部。

  5. 如果你找到了一个不再需要的大文件/目录,可以以适当的方式删除它。不要担心输出顶部的小目录。如果你删除它们,问题不会得到解决。如果你仍然没有足够的空间,那么你可以在列表底部显示的最大子目录中重复第4步。

但是如果du的输出与df显示的可用空间不相符,会发生什么呢?
如果du的输出较大,则表示你错过了一个挂载了另一个文件系统的子目录。如果du的输出较小,则表示某些文件没有显示在du检查的任何目录中。这可能有不同的原因。
一些进程正在使用已经被删除的文件。因此,这些文件已从目录中移除,du命令无法看到它们。但是对于文件系统来说,直到进程关闭文件,它们的块仍然在使用中。您可以尝试找出相关的进程(例如使用lsof命令),并强制它们关闭这些文件(例如停止应用程序或杀死进程)。或者您可以简单地重新启动机器。
有些目录中的文件不再可见,因为它们的父目录之一挂载了另一个文件系统。所以如果您有一个文件/myfilesystem/subdir/bigfile,并且现在在/myfilesystem/subdir上挂载了另一个文件系统,那么您将无法再看到这个文件,并且
du -shx /myfilesystem
将报告一个不包含/myfilesystem/subdir/bigfile大小的值。唯一的方法是卸载/myfilesystem/subdir并检查其中是否包含文件。
可能存在一些特殊类型的文件系统,它们在磁盘上使用/保留空间,但这些空间对ls命令不可见。您需要使用特殊工具来显示这些文件系统。
除了使用du命令的系统化方法之外,还有其他一些方法可以使用。因此,您可以使用find命令查找大于您提供的某个值的文件,您可以搜索大于您提供的某个值的文件,或者新创建的文件或具有特殊名称的文件(例如*.log,core,*.trc)。但是,您始终应该像第1点中描述的那样执行df,以便在正确的文件系统上进行操作。

在一个繁忙的服务器上,你不能总是卸载东西。但是你可以将上层目录绑定挂载到一个临时位置,它不会包含其他挂载点,并且允许访问隐藏文件。 - Zan Lynx
在使用systemd之前,我经常遇到挂载失败导致根目录(/)被垃圾填满的情况。例如,在没有连接USB驱动器的情况下,将备份写入/mnt/backup。现在,我确保这些作业单元具有挂载要求。 - Zan Lynx
@ZanLynx 谢谢你,我之前从来没有听说过绑定挂载 - miracle173
@ZanLynx:不仅仅是在繁忙的服务器上。想象一下,你在一个单独的文件系统(例如tmpfs)上有一个/tmp目录,并且在它成为另一个文件系统的挂载点之前,某些东西在/tmp中创建了文件。现在这些文件位于根文件系统中,被挂载点遮盖,你无法在不重启到恢复模式(该模式不处理/etc/fstab)或者像你建议的那样进行绑定挂载的情况下访问它们。 - David Foerster

我经常使用这个。
du -sh /*/

然后,如果我发现一些大的文件夹,我会切换到它并进行进一步的调查。
cd big_dir
du -sh */

如果需要的话,你也可以让它自动排序。
du -s /*/ | sort -n

尝试运行sudo apt-get autoremove命令来删除未使用的文件,如果你还没有这样做的话。

1之前已经做过了:( 但对其他人来说是个好主意! - Karl Morrison

不是真正的答案,而是一个附录。

你的空间已经用完了,无法从 @erman 的回答中安装 ncdu。

一些建议:

  • sudo apt clean all 删除已经下载的软件包。安全
  • sudo rm -f /var/log/*gz 清理一周或两周前的日志文件 - 不会删除较新/当前的日志。大部分安全
  • sudo lsof | grep deleted 列出所有打开的文件,但只显示已从磁盘上删除的文件。相对安全
  • sudo rm /tmp/* 删除一些临时文件 - 如果有进程正在使用它们,可能会干扰该进程。并不是非常安全

那个 `lsof` 命令可能会返回类似以下的行:

server456 ~ $ lsof | grep deleted
init          1          root    9r      REG              253,0  10406312       3104 /var/lib/sss/mc/initgro                        ups (deleted)
salt-mini  4532          root    0r      REG              253,0        17     393614 /tmp/sh-thd-1492991421                         (deleted)

初始行无法做太多事情,但第二行建议salt-minion打开了一个已删除的文件,并且一旦由服务重新启动关闭所有文件句柄,则磁盘块将返回。

其他常见嫌疑人包括syslog / rsyslog / syslog-ng、squid、apache或任何您的服务器运行的“重型”进程。


我发现像Filelight这样的工具的输出特别有价值,但是像你的情况一样,在服务器上通常没有安装图形界面,但是du命令始终可用。
我通常的做法是:
- 将du的输出写入文件(du / > du_output.txt); - 将文件复制到我的计算机上; - 使用DuFS在临时目录中“挂载”du的输出;DuFS使用FUSE根据du的输出创建一个虚拟文件系统(实际上没有创建任何文件,都是虚假的); - 在这个临时目录上运行Filelight或其他图形界面工具。
免责声明:我编写了dufs - 正是因为我经常需要找出无头机器上占用磁盘空间的原因。

你可以直接使用“sort -n du_output.txt”命令进行排序。 - Zan Lynx
我觉得使用空间的图形显示更直观。 - Matteo Italia