![如何遍历文件并删除那些早于 x 天但未使用的文件](https://linux22.com/image/77358/%E5%A6%82%E4%BD%95%E9%81%8D%E5%8E%86%E6%96%87%E4%BB%B6%E5%B9%B6%E5%88%A0%E9%99%A4%E9%82%A3%E4%BA%9B%E6%97%A9%E4%BA%8E%20x%20%E5%A4%A9%E4%BD%86%E6%9C%AA%E4%BD%BF%E7%94%A8%E7%9A%84%E6%96%87%E4%BB%B6.png)
所以,我自己已经能够弄清楚其中的一些内容,但很难将它们拼凑在一起。我有一个需要自动化的任务 - 我的文件夹中充满了千兆字节的过时文件,如果它们满足两个条件,我想清除它们。
- 文件在过去 14 天内不得被修改 - 为此,我使用 find -
find /dir/* -type f -mtime +14
- 并且文件不能被使用,这可以通过以下方式确定
lsof /dir/*
我对 bash 还不太了解,还不知道如何组合这些命令。如有帮助,将不胜感激。我想我本质上是想循环遍历 find 的每一行输出,检查它是否存在于 lsof 的输出中,如果没有,则 rm -f ——但是,如果它们实现了目标,我愿意接受替代方法!
答案1
以下应该有效:
for x in `find <dir> -type f -mtime +14`; do lsof "$x" >/dev/null && echo "$x in use" || echo "$x not in use" ; done
echo "$x not in use"
您可以放置您的命令,而不是命令rm "$x"
。
它是如何工作的:
- 查找上次修改时间为 14 天或更长时间之前的文件:
find <dir> -type f -mtime +14
- 循环列表中的项目:
for x in <list>; do <command>; done
lsof
如果结果为则执行命令 20
,否则执行命令 1:
lsof "$x" && <command 1> || <command 2>
这依赖于惰性评估Bash 执行命令 1 或命令 2。
在我的系统(Ubuntu 14.04)上,这适用于其中包含空格的文件名,甚至适用于其中包含?
和的文件名。 但这并不能保证它适用于任何系统上的每个 shell。请在用命令替换命令之前进行测试。*
echo
rm
答案2
使用-exec
find 中的操作对每个文件执行命令。这将执行一个带有参数的程序;如果您需要更复杂的命令(带有变量扩展、条件等),那么您需要显式调用 shell:
find /dir/* -type f -mtime +14 -exec sh -c '
if …; then
rm "$0"
fi
' {} \;
要测试文件当前是否打开,最直接的方法是调用fuser
。
find /dir/* -type f -mtime +14 -exec sh -c '
if ! fuser "$0" >/dev/null 2>/dev/null; then
rm "$0"
fi
' {} \;
请注意,仅仅因为文件很长时间没有被修改并且当前没有打开并不意味着它没有用。我建议至少测试一下该文件有一段时间没有被读取;这可以用访问时间来测试,但要注意 Linux 系统不会可靠地更新访问时间。 (是否执行以及执行的频率取决于内核版本、挂载选项以及访问时间与修改时间的比较情况。)
我建议在删除文件之前先检查它们。
find /dir/* -type f -mtime +14 -atime +14 -exec sh -c '
if ! fuser "$0" >/dev/null 2>/dev/null; then
echo "$0"
fi
' {} \; >files-to-delete-potentially.txt
检查文件名,然后删除要保留的文件名。然后要将它们全部删除,假设所有文件名都不包含换行符,您可以使用
<files-to-delete-potentially.txt tr '\n' '\0' | xargs -0 rm
答案3
我建议使用or选项,而不是使用lsof
具有噩梦般的选项和有趣的解析输出的 which 。这些允许您分别指定文件访问时间(以天或秒为单位)。-atime
-amin
find
您可以检查是否在过去 N 秒或几天内被访问过,而不是使用另一个进程来查明文件当前是否“正在使用”。
以下命令列出了超过 14 天前修改且访问时间少于 60 秒的所有文件。
find "$dir" -type f -mtime +14 -amin -60
要删除符合此条件的文件,您可以使用find
的-exec command ;
命令。奇怪的是,您单独指定每个命令参数来查找并以分号 ( ;
) 终止。如果{}
出现在任何参数中,它将被替换为正在处理的文件的名称。
此命令将删除 14 天前创建的所有文件,并且在过去 60 分钟内未访问过:
find "$dir" -type f -mtime +14 -amin -60 -exec rm '{}' \;