linux下超百万文件目录的遍历或删除
今天在群里有个群友问了个问题,生产环境有目录包含数量较多的文件,删除会被卡住,自己想了下发现自己这点没遇到过但是确实存在这个情况就去了解学习了下,这里做一下小结
生成测试文件
初始测试文件这里生成300w个文件(其实生成也需要一点时间,我测试的时候跑到120w左右的样本就能明显感受差别了)
#!/bin/bash dir=/root/data/tmp/files for((i=1;i<3000000;i++)); do file=$dir"/"$i".txt" touch $file echo $file"......done" done
遍历文件
#!/bin/bash function scanDir(){ for file in `ls -f $1` do curFile=$1"/"$file if [ -d $curFile ] then scanDir $curFile else echo $curFile fi done } scanDir $1
其实 一般直接 ls 遍历就可以 但是 ls 遍历会卡住
这是因为默认情况下ls输出的是经过排序过的,为了排序自然要开辟内存进行运算,那么需要消耗很大的空间和计算
那么ls -f 命令能够不执行排序操作,读取了就立即输出,
linux具体文件目录组织方式还有ls排序的原理可以回头单开一篇这里就不多深入了
经过测试(肉眼+秒表)
在100w的文件数量的目录里面
ls 遍历需要4秒
ls -f 不用排序 do not sort, enable -aU, disable -ls --color ls -1 输出长格式列表(这个在help里面没有)
删除文件
一般我们直接用 rm -rf ./* 就可以但是 当目录文件过多的时候会报错这是因为
linux下面的命令长度和参数数量都是有限制的
操作系统受参数ARG_MAX的限制
[root@VM-88-103-centos ~/data/tmp/files]# getconf ARG_MAX 2097152
操作系统受参数LINE_MAX的限制
[root@VM-88-103-centos ~/data/tmp/files]# getconf LINE_MAX 2048
所以删除 rm -rf ./* 如果文件超过数量是会报错的
[root@VM-88-103-centos ~/data/tmp/files]# rm -rf ./* -bash: /usr/bin/rm: Argument list too long
所以删除的时候可以用上面的脚本遍历删除
同理的也可以用
find . -name "*" | xargs rm
查看卡住的进程在干嘛
在命令或者进程卡住的情况下 怎么知道进程在干嘛呢 可以用strace命令
首先找到pid然后
strace -p 3963 unlinkat(4, "227219.txt", 0) = 0 unlinkat(4, "227249.txt", 0) = 0 unlinkat(4, "227253.txt", 0) = 0 unlinkat(4, "227254.txt", 0) = 0 unlinkat(4, "227255.txt", 0) = 0 unlinkat(4, "227258.txt", 0) = 0 unlinkat(4, "227268.txt", 0) = 0 ......
就可以看到这个进程到底在干嘛了
其实首先 卡住这个如果目录过多 肯定会消耗比一般情况下更多的时间的,删除的操作时间是固定的,那么能解决的就是查找文件的操作,
减少不必要的操作,不用一次性全部获取 可以找到一个删除一个。这样能大大减少卡住的时间。