我有一个充满日志的目录,其名称如下:
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
表达式。这是一种无害的黑客行为。