为何非递归find命令比ls+grep组合搜索日志慢如此之多?
为什么两个日志搜索脚本的耗时差异如此巨大?
先看你编写的两个脚本:
Script 1(耗时24分钟)
current_date=$(date +"%m-%d-%Y") logsPath="/hadoop_common/smallsite/realtime/current/spark/logs" find $logsPath -maxdepth 1 -name "*$current_date*" -print > tmp
Script 2(耗时16秒)
current_date=$(date +"%m-%d-%Y") logsPath="/hadoop_common/smallsite/realtime/current/spark/logs" ls $logsPath | grep "$current_date" > tmp sed -i "s|^|$logsPath|" tmp
核心差异在于两个工具的工作机制完全不同,尤其是当目录下存在大量文件(你这里匹配出2367个结果,实际目录内的文件总数只会更多)时,这种差异会被无限放大:
1. find命令的低效根源
find是为复杂查找场景设计的工具(比如递归遍历子目录、按权限/大小/修改时间筛选等),哪怕你加了-maxdepth 1限制只查当前目录,它依然会对目录下的每一个条目执行stat()系统调用——这个调用会读取文件的元数据(比如文件类型、权限、修改时间等),哪怕你根本不需要这些信息,只是想匹配文件名。
当文件数量极多时,大量的stat()调用会触发频繁的磁盘IO(如果文件元数据不在系统缓存中),这会严重拖慢执行速度,这就是第一个脚本耗时24分钟的核心原因。
2. ls + grep组合的高效逻辑
ls在不带-l这类需要读取元数据的参数时,会使用getdents()系统调用批量读取目录下的所有文件名——这个调用一次性就能获取目录里的所有条目,不需要对每个文件单独做stat(),开销极小,几乎瞬间完成。
之后的grep只是在内存中对ls输出的文本做字符串匹配,属于用户空间操作,速度非常快。最后的sed也只是给匹配到的文件名加上路径前缀,同样是内存中的字符串处理,几乎不占用额外时间。
额外优化建议
如果想用find接近ls + grep的速度,可以尝试添加-type f(如果仅查找文件)或-mindepth 1参数,但即便如此,find依然会执行stat()检查,还是不如ls + grep轻量。对于单纯的文件名匹配场景,ls + grep确实是更高效的选择。
内容的提问来源于stack exchange,提问作者X625
相关产品推荐
相关产品推荐

