将 mtime 添加到 grep -c 输出并按 mtime 对输出进行排序

将 mtime 添加到 grep -c 输出并按 mtime 对输出进行排序

我有一个充满日志的目录,其名称如下:

info.log00001
info.log00002
info.log00003
...
info.log09999
info.log


我当前的输出(使用 grep -c)

我需要分析偶尔发生的特定错误的频率,因此请转到该目录并使用grep -crw . -e "FooException BarError" | sort -n | less获取类似以下内容的内容:

./info.log00001: 1
./info.log00002: 0
./info.log00003: 42
...
./info.log09999: 25
./info.log: 0

然后,我可以ls -lt看到他们的修改日期并分析错误发生最多的时间。


我想要的输出(带有计数和日期)

不管怎样,我想找到一种方法来获得计数和日期在同一行的输出。这将使我的分析更容易。我想要这样的东西:

2015-09-31 10:00 ./info.log00001: 1
2015-09-31 10:15 ./info.log00002: 0
2015-09-31 10:30 ./info.log00003: 42
...
2016-04-01 13:20 ./info.log09999: 25
2015-09-31 13:27 ./info.log: 0


附加信息

理想情况下,我想只用一个命令来完成此任务,但首先将grep的输出扔到一个文件中,然后处理该文件也可以实现。

另外,我真的不关心日期格式或日期是在行的末尾还是在行的开头。我想要的只是让文件按日期从最旧的开始排序(这也是名称中数字最小的文件)

我找到了一种方法来实现类似的东西awk,但在我的情况下,它不起作用,因为它从grep的输出中解析文件名,并且在我的情况下,grep的输出包含更多文本,而不仅仅是文件的路径。

我真的很感激任何对此的反馈。

答案1

如果你有gnu find- 并且假设你的文件名都不包含换行符 - 你可以使用find's-printf以所需的格式输出mtime+ 文件名,然后运行grep以获取计数:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM %p: ' -exec grep -cw "whatever" {} \; | sort -k1,1 -k2,2

或者,zsh您可以按修改时间进行全局排序(通过全局限定符-.选择常规文件,Om按降序排序时间)然后对于每个文件mtime使用打印stat模块、文件名,然后再次通过以下方式获取计数grep

zmodload zsh/stat
for f in ./**/*(.Om)
do
printf '%s %s\t%s %s: ' $(zstat -F '%Y-%b-%d %H:%M' +mtime -- $f) $f
grep -cw "whatever"  $f
done

答案2

bash 构造

shopt -s globstar
join -o 1.2,0,2.2 -t$'\034' <(stat -c $'%n\034%y' ** | sort) \
                            <(grep -crw "..." | sort | sed -r $'s/:([^:]*)/\034\\1/') \
                             | tr '\034' '\t'

里面有一些有趣的东西\034——那就是角色的八进制值FS。这是可以想象的如果您的现有文件名中包含该字符,则可以根据需要更改该分隔符。

stat命令递归地输出每个文件的文件名和修改时间。

您熟悉 grep 命令。我将最后一个冒号翻译为 FS 字符。

我必须对 stat 和 sed 使用 bash 的 ANSI-C 引用语法来获取其中的 FS 字符。

join命令将 stat 的输出与 grep 的输出连接起来,并输出“date FS filename FS count”

然后我将 FS 转换为普通选项卡。

答案3

基于 Perl 的解决方案:

perl -lne 'if ($.==1) {
 print localtime($t)." $f: $c\n" if defined $t; 
 $c=0; $f=$ARGV; $t=(stat($f))[7];} $c++ if /$expr/o; 
} BEGIN { $expr=shift @ARGV; push @ARGV,"/etc/hosts"; 
' "search-expression" info.log

注:未经测试。

这里有一些标准的 Perl 技巧。-n环绕while (<>) {你的代码。什么时候$.为1时,是一个新文件。如果我们处理了一个文件,则打印出摘要信息 - 时间戳、文件名、计数。现在,仅针对第一行,获取当前文件名、文件的 mtime 时间戳,并重置计数器。对于每一行,如果计数器与所需的正则表达式匹配,则递增计数器。结束while循环并开始一些启动代码,该代码被执行前一个块。将第一个参数作为每行匹配的正则表达式。现在,对于参数列表,删除第一个参数。然后,附加一个虚拟文件添加到 arg 列表中,它将触发最终的print表达式。这是一种无害的黑客行为。

相关内容