Priest Tomb



Linux 从大量文件中找出部分文件并删除

1 磁盘爆了

项目中一段逻辑不完善的代码,向一个目录不断上传图片文件,同时没有删除逻辑,当因为磁盘满了发现问题时,已经写了 200GB、600W+ 文件,并且还在继续。

其中有非常小一部分图片是有用、不能删的,大部分图片需要清理,于是有了本文的两种尝试(最后发现多绕了亿点弯路,但终究还是学习了几个 Linux 命令哈哈)。

本文没有详细介绍命令如何使用,网上相关的文章很多,可自行查找学习。

2 首先

重点中的重点,先修改有问题的代码,虽然新的图片文件还在上传,但被其替换的无用图片由新的逻辑控制主动删除。


混入防转防爬防抄袭声明:本文《Linux 从大量文件中找出部分文件并删除》首发且仅发布于没有名字的博客


3 找出文件

接下来要做的是找到要删除的文件,当然,目前目录下文件数量过多,实在是打印不出来,这些命令只是单独拿出来介绍和解释。

在这个问题中,通过查询数据库,得知了一些时间段的文件可以删,所以下面的命令都是按指定时间段查询符合条件的文件。

3.1 find 命令

find . -type f -mtime +9 -mtime -15 -print

or

touch -t 202208150000 t_start
touch -t 202209232359 t_end
find . -type f -newer t_start ! -newer t_end -print

第一种写法是用 -mtime 指定文件的修改时间在过去 10 到 15 天范围内,因为需要算天数,而且 +N 的计算还很奇怪(实际是 (n + 1) 天以前),再加上这个目录下有几百万文件,不太可能列出来看一遍再决定对不对,于是找到了第二种写法。

第二种是先使用 touch 命令创建两个时间戳文件,用 -newer 指定与这两个时间戳文件比较,得到符合条件的文件,这个写法就比较直观,touch 命令可以控制精确到秒的时间戳,所以尝试用此命令。

3.2 ls 命令

找到 find 命令后,在服务器(实际是 Docker 容器)中执行,提示没有此命令。。一阵无语,就随手搜一下其他方案,找到了 ls 命令的写法,虽然最后是在真实服务器上用 find 命令操作,但这个写法也挺有意思,于是记下来。

ls -f --full-time | grep -E "2022-08-15|2022-08-16|2022-08-17"

使用 --full-time 打印出完整的日期时间,再结合 grep 过滤找出相应日期的文件。

4 删除文件

结合上述两种查找命令,分别有各自的删除写法。

4.1 find 命令

find . -type f -mtime +9 -mtime -15 -exec rm -rf {} \;

or 

find . -type f -mtime +9 -mtime -15 | xargs rm -rf

第一种是用 find 命令自带的 -exec,用 {} 代替查找出的结果,同时这个 -exec 参数的末尾必须有空格,否则会报 find: 遗漏“-exec”的参数,所以就变成了接一个空格,再用 \; 结尾。

第二种是用管道的方式,接 rm 命令。

4.2 ls 命令

rm -rf $(ls --full-time | grep -E "2022-08-15|2022-08-16|2022-08-17" | awk '{print $9}')

or

ls -f --full-time | grep -E "2022-08-15|2022-08-16|2022-08-17" | awk '{print $9}' | xargs rm -rf

第一种是用 ls 的结果替换给 rm 执行,要注意后面的 awk,使用 --full-time 后,输出的内容不仅仅是文件名,还包含其他列,所以使用 awk 只输出第 9 列,即文件名。

第二种同样是使用管道,接 rm 命令即可,同理,需要用到 awk 辅助。

5 兜圈子

借助 findrm,把确定的一些时间范围内的无用文件清理之后,发现还剩了 100W+ 图片文件,此时才开始反向思考一个问题,其实数据库保存的信息中有那些不需要删除的图片的名称,为什么不先把这些图片文件单独复制出来,再把目录清空,再将它们还原回来。。

于是,浪费了不少时间之后,最终还是采用了这样的最直接了当的方法,当然,学习尝试了几个以前没用过的命令也是个小收获。