awk 实用程序如何在此命令中处理多格式时间戳

How can awk utility process multi-format timestamps in this command

我正在根据时间范围(即两个时间戳之间)从日志文件中提取内容。

这是我用来提取过滤内容的方法:

awk --assign start='2020-09-13T00:25:15' --assign end='2020-09-13T00:25:19' 
'/^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} / { inrange = [=10=] >= start && [=10=] <= end } inrange' 
< path/to/my/file

如果日志文件中的时间戳采用“yyyy-MM-ddTHH:mm:ss”格式,效果会很好。 但是,不同的日志文件有不​​同的格式。 因此,例如,我需要 运行 格式为“yyyy-MM-dd HH:mm:ss”的不同命令。 它将是:

awk --assign start='2020-09-13 00:25:15' --assign end='2020-09-13 00:25:19' 
'/^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} / { inrange = [=11=] >= start && [=11=] <= end } inrange' 
< path/to/my/file

如何统一我的命令以适应像“yyyy-MM-dd.HH:mm:ss”这样的格式,其中点是任何字符,如正则表达式?

我试过

awk --assign start='2020-09-13/./00:25:15' --assign end='2020-09-13/./00:25:19' 
'/^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} / { inrange = [=12=] >= start && [=12=] <= end } inrange' 
< path/to/my/file

没用。

这是测试的示例数据:

2020-09-13T00:25:14.968+0300: line1
2020-09-13T00:25:14.969+0300: line2
2020-09-13T00:25:16.000+0300: line3
2020-09-13T00:25:16.001+0300: line4
2020-09-13T00:25:16.200+0300: line5
NullPointerException          line6
caused by:                    line7
some code at some line.       line8
this is without timestamps    line9
2020-09-13T00:25:18.000+0300: line10
2020-09-13T00:25:19.000+0300: line11
2020-09-13T00:25:20.000+0300: line12
2020-09-13T00:25:40.000+0300: line13

我的命令应该在 2020-09-13 00:25:15 到 2020-09-13 00:25:19.

的时间间隔内提取行

预期输出:

2020-09-13T00:25:16.000+0300: line3
2020-09-13T00:25:16.001+0300: line4
2020-09-13T00:25:16.200+0300: line5
NullPointerException          line6
caused by:                    line7
some code at some line.       line8
this is without timestamps    line9
2020-09-13T00:25:18.000+0300: line10
2020-09-13T00:25:19.000+0300: line11

现在想象一下时间戳为 2020-09-13 的相同日志数据 00:25:16.000+0300 或 2020-09-13t00:25:16.000+0300,- 它仍然必须产生相同的预期输出。

允许输入变量中的模式并没有多大意义。也许更新代码以规范化变量中的信息。

awk -v start='2020-09-13T00:25:15' -v end='2020-09-13T00:25:19' \
'!(FILENAME in known) && /^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}T/ {
  if (start !~ /T/) sub(" ", "T", start)
  if (end !~ /T/) sub(" ", "T", end)
  known[FILENAME] = "T" }
!(FILENAME in known) && /^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2} / {
  if (start ~ /T/) sub("T", " ", start)
  if (end ~ /T/) sub("T", " ", end)
  known[FILENAME] = " " }
/^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}[ T]/ { inrange = [=10=] >= start && [=10=] <= end} inrange' path/to/my/file

代码略显笨重且重复,但它应该相当快并且很明显这里发生了什么。如果变量中的格式与此文件中的格式不一致,请更改变量。首先对 start 执行此操作(转换为具有 space 而不是 T,如果这是文件中的内容,反之亦然),然后对 end 执行此操作。 known 关联数组被更新以将当前文件(其名称在 FILENAME 中)标记为已检查,以避免对文件中的每个后续行重复执行相同的检查。这显然假设文件内的格式是一致的。

(另请注意我是如何稍微重构最后一行的。您最初的尝试不允许 T 在日期之后,因此它可能实际上不适用于您的第一个示例。我切换到 -v 优先于 --assign,因为后者不可移植。)

您需要做的就是将输入的日期和时间之间的字符设置为空白或 T(或者您想要在开始和结束时间戳中使用的任何内容)命令行)在将其与那些范围定界符进行比较之前:

awk -v beg='2020-09-13 00:25:15' -v end='2020-09-13 00:25:19' '
    match([=10=],/^[0-9]{4}(-[0-9]{2}){2}/) {
        cur = substr([=10=],1,RLENGTH) " " substr([=10=],RLENGTH+2,8)
        inrange = (beg <= cur && cur <= end)
    }
    inrange
' file
2020-09-13T00:25:16.000+0300: line3
2020-09-13T00:25:16.001+0300: line4
2020-09-13T00:25:16.200+0300: line5
NullPointerException          line6
caused by:                    line7
some code at some line.       line8
this is without timestamps    line9
2020-09-13T00:25:18.000+0300: line10