如何从时间戳后可以跟多行日志的日志文件检索数据

如何从时间戳后可以跟多行日志的日志文件检索数据

我有一个日志文件,我试图通过 bash 脚本“grep”数据。我特别关注的数据是两个时间戳之间的所有行(包括顶部时间戳),这些行具有模式“ERR-”,并且在每个条目之后包含一个空行以提高可读性。

示例日志文件:

Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
Tue May 24 21:47:25 2022
im some output
Tue May 24 21:47:25 2022
im some output too
im some output aswell
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421
Tue May 24 21:49:07 2022
Completed process xyz

所以我想要的输出如下:

Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
    
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
        
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421

我尝试过使用 sed/awk/cat 的组合,但没有取得太大成功。我遇到麻烦的地方是:

  1. ERR 之前并不总是包含时间戳的两行
  2. 一个时间戳块中可以有多个 ERR-
  3. 日期显然会改变,所以我不想硬编码,尽管格式不会改变。

提前致谢

答案1

脚本tst.awk

function print_r() { if (e) print r; r = ""; e = 0 }

/^([[:alpha:]]{3} ){2}[[:digit:]]{1,2} [[:digit:]]{2}(:[[:digit:]]{2}){2} [[:digit:]]{4}$/ {
    print_r()
}
/^ERR-/{ e = 1 }
{ r = r ORS $0 }
END{ print_r() }

用法和输出:

$ awk -f tst.awk file

Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck

Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log

Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421

您可以使用自己的表达式来表示时间戳或错误。这是所呈现格式的整行匹配(无日期验证)。并在行的开头添加“ERR-”。


笔记:

  • r我们定义一个函数,如果发现错误 ( ),则打印记录 ( ) e。打印后还要重置这两个变量。对于awk,尚未用值初始化的变量将被计算为空字符串或零。

  • 当日期的正则表达式匹配时,我们调用此函数。完成之前的日志记录并开始保存新的记录。因为记录是多行日志,所以我们还不知道是否必须打印它。

  • 当错误模式匹配时,我们设置e

  • 对于每一行,我们将行追加到现有记录中,并用ORS输出记录分隔符(默认换行符)分隔。此外,输出行之间的空行放置在 的开头rr当我们在这里获取新时间戳时,始终是空字符串。

  • 我们END再次调用该函数,因为最后一条记录仍然保留着。

答案2

使用(以前称为 Perl_6)

~$ raku -e 'my @a=slurp; @a.=split(/ <?after ^^ ERR \V* > \n <?before ^^ Tue > /); \
            put $_.subst(/^ <(.+)> ^^ Tue/) ~ "\n" if /^^ ERR / for @a;'   file

问题似乎是您有一些带时间戳的记录有ERR行,有些没有,您想丢弃后者。

上面,文件被slurp编入@a数组。 Then@a位于以 开头的行结尾的记录之间split,后跟零个或多个非垂直空白字符,以及以 开头的行之前。\n<?after ^^ ERR \V* >ERR\V<?before ^^ Tue >Tue

在第二个声明中,output(…)被精炼了。这些元素在该条款的序言中@a单独(自动)表示。每个元素都经过条件测试,以确保它们包含以:开头的行,因此,该元素将被替换,删除前面的所有前导字符$_forif /^^ ERR/ERRif$_$_.subst(/^ <(.+)> ^^ Tue/)内部的行首Tue.本质上,这里.subst没有替换意味着删除<()>捕获标记之间的匹配。为了分隔各个记录,$_.subst(…) ~ "\n"元素通过~波浪号与记录分隔"\n"换行符连接起来。

输入示例:

Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
Tue May 24 21:47:25 2022
im some output
Tue May 24 21:47:25 2022
im some output too
im some output aswell
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421
Tue May 24 21:49:07 2022
Completed process xyz

示例输出:

Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck

Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log

Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421

当然,上面是一个简单的实现(它的目的是为了可读性)。要处理从一周中其他日子开始的日期,请将Tues上面的内容替换为以下内容:

 [ Mon || Tue || Wed || Thu || Fri || Sat || Sun ] 

(如果您遇到特殊性问题,从上面的代码中应该可以清楚地看出如何向正则表达式添加月份)。

https://raku.org

相关内容