我知道这不是一件容易的事,因为grep将搜索结果输出到STDOUT,我的默认工作流是我将结果输出到文件,并希望将进度条/状态输出到STDOUT或STDERR.
理想的命令是:
grep -e“STRING”–results =“FILE.txt”
和进展:
[curr file being searched],number x/total number of files
写入STDOUT或STDERR
我知道这不是一件容易的事,因为grep将搜索结果输出到STDOUT,我的默认工作流是我将结果输出到文件,并希望将进度条/状态输出到STDOUT或STDERR.
理想的命令是:
grep -e“STRING”–results =“FILE.txt”
和进展:
[curr file being searched],number x/total number of files
写入STDOUT或STDERR
如果您通过单次调用grep来搜索“数千个文件”,则很可能是使用-r选项递归目录结构.在这种情况下,甚至不清楚grep是否知道它将检查多少文件,因为我相信它在探索整个目录结构之前就开始检查文件.首先探索目录结构可能会增加总扫描时间(实际上,生成进度报告总是有成本,这就是为什么很少有传统的Unix实用程序这样做的原因.)
在任何情况下,可以通过构造要扫描的文件的完整列表然后将它们以一定大小(可能是100)或可能基于批次的总大小的批量馈送到grep来获得简单但稍微不准确的进度条.小批量将允许更准确的进度报告,但是它们也会增加开销,因为它们需要额外的grep进程启动,并且进程启动时间可能不仅仅是对一个小文件进行grepping.将针对每批文件更新进度报告,因此您需要选择批量大小,以便定期更新,而不会增加过多的开销.将批处理大小基于文件的总大小(例如,使用stat来获取文件大小)将使进度报告更精确,但会增加处理启动的额外成本.
这种策略的一个优点是你也可以并行运行两个或多个greps,这可能会加快这个过程.
从广义上讲,这是一个简单的脚本(它只是按计数划分文件,而不是按大小划分,并且不会尝试并行化).
# Requires bash 4 and Gnu grep shopt -s globstar files=(**) total=${#files[@]} for ((i=0; i<total; i+=100)); do echo $i/$total >>/dev/stderr grep -d skip -e "$pattern" "${files[@]:i:100}" >>results.txt done
为简单起见,我使用globstar(**)将所有文件安全地放入数组中.如果您的bash版本太旧,那么您可以通过循环查找输出来完成它,但如果您有大量文件则效率不高.不幸的是,我不知道写一个只匹配文件的globstar表达式. (** /只匹配目录.)幸运的是,GNU grep提供-d skip选项,它以静默方式跳过目录.这意味着文件计数会稍微不准确,因为目录将被计算,但它可能没有多大区别.
您可能希望使用某些控制台代码使进度报告更清晰.以上只是为了让你入门.
将其划分为不同进程的最简单方法是将列表划分为X个不同的段,并为循环运行X,每个循环都有不同的起点.但是,它们可能不会同时完成,因此不是最佳的.更好的解决方案是GNU并行.你可能会这样做:
find . -type f -print0 | parallel --progress -L 100 -m -j 4 grep -e "$pattern" > results.txt
(这里-L 100指定每个grep实例最多应该给出100个文件,-j 4指定四个并行进程.我只是将这些数字从空中拉出来;你可能想调整它们.)