![如何在 Linux 上安全地清理 tmp 文件夹](https://linux22.com/image/1336990/%E5%A6%82%E4%BD%95%E5%9C%A8%20Linux%20%E4%B8%8A%E5%AE%89%E5%85%A8%E5%9C%B0%E6%B8%85%E7%90%86%20tmp%20%E6%96%87%E4%BB%B6%E5%A4%B9.png)
我为 tmpfs /tmp 使用了 2GB 的 RAM。通常,这已经足够了,但有时,进程会在其中创建文件,但无法自行清理。如果它们崩溃,就会发生这种情况。我需要删除这些孤立的 tmp 文件,否则未来的进程将耗尽 /tmp 上的空间。
我如何安全地对 /tmp 进行垃圾回收?有些人通过检查上次修改时间戳来做到这一点,但这种方法不安全,因为可能存在需要这些文件的长期运行的进程。更安全的方法是将上次修改时间戳条件与没有进程拥有该文件的文件句柄的条件结合起来。是否有程序/脚本/等体现这种方法或其他同样安全的方法?
顺便问一下,Linux/Unix 是否允许一种文件打开模式,其中当创建过程终止时,创建的文件会被删除,即使是由于崩溃?
答案1
您可能想尝试这样的事情:
find /tmp -mtime +7 -and -not -exec fuser -s {} ';' -and -exec echo {} ';'
find 用于查找符合特定条件的文件。
-mtime +7
仅选择超过 7 天的文件(您可以使用任何其他值)-exec fuser -s {} ';'
以静默模式调用 fuser 来处理符合旧度标准的每个文件。fuser 为每个当前已访问的文件返回 0(= true),为未访问的文件返回 1(= false)。由于我们只对未访问的文件感兴趣,因此我们-not
在此前面放置了一个-exec
-exec echo {} ';'
仅打印符合条件的所有文件名。您可能想-exec rm {} ';'
在这里使用,但由于这可能会删除一些仍在使用的文件,我认为先做一个简单的回声更安全。- 编辑:您可能需要添加类似的内容
-name 'foo*.bar'
或-uid 123
将清理的效果限制在特定的文件模式或用户 ID 内,以避免意外影响。
最后一点:考虑到可能存在只写入一次(例如在系统启动时)但读取频繁(例如任何 X-session-cookie)的文件。因此,我建议添加一些名称检查,以仅影响由错误程序创建的文件。
编辑2: 最后一个问题:除非没有进程打开该文件的句柄(至少对于原生 Linux 文件系统而言),否则文件不会从磁盘中删除。问题是目录条目会立即被删除,这意味着从删除文件时起,没有新进程可以再打开该文件(因为没有附加文件名)。
有关详细信息,请参阅: https://stackoverflow.com/questions/3181641/how-can-i-delete-a-file-upon-its-close-in-c-on-linux
编辑3:但是如果我想让整个过程自动化该怎么办?
正如我所说,可能存在只写入一次然后每隔一段时间读取一次的文件(例如 X 会话 cookie、PID 文件等)。这些文件不会被这个小删除脚本排除(这就是为什么您可能想在echo
实际删除文件之前先进行测试运行的原因)。
实现安全解决方案的一种方法是使用atime
。
atime
存储每个文件上次访问的时间。但该文件系统选项通常被禁用,因为它对性能有相当大的影响(根据这个博客在 20-30% 范围内的某个地方)。有relatime
,但是那个只在访问时间mtime
发生变化时写入,所以这个对我们没有帮助。
如果您想使用atime
,我建议将其放在/tmp
单独的分区(最好是 ramdisk)上,这样对整个系统的性能影响就不会太大。
一旦atime
启用,您所要做的就是将-mtime
上述命令行中的参数替换为-atime
。
您也许可以删除-not -exec fuser -s {} ';'
,但我会将其保留在那里以确保万无一失(以防应用程序长时间保持文件打开)。
但请记住echo
在删除系统仍然需要的东西之前使用该命令进行测试!
答案2
不要自己动手。
Debian/Ubuntu 有 tmpreaper,它可能也在其他发行版中可用。
# tmpreaper - cleans up files in directories based on their age
sudo apt-get install tmpreaper
cat /etc/tmpreaper.conf
答案3
答案4
获取早于 so 的文件列表,排除由该列表中的任何内容打开的文件:
find /tmp -mtime +7 |\
egrep -v "`lsof -n +D /tmp | awk 'NR>1 {print $9}'| tr \\n \|`"
lsof -n +D /tmp
:在 /tmp 中查找打开的文件
awk 'NR>1 {print $9}'
:仅打印 lsof 输出的第九列,不包括标题
tr \\n \|
:用 bar 替换换行符(在 egrep 中为 OR)
egrep -v "foo|moo|bar"
:打印不包含 foo 或 moo 或 bar 的行