在日志中搜索正则表达式模式,然后再次在周围的行中搜索上一个匹配项



我有一个日志,其中包含来自处理身份验证的进程的行。这种认证通常由4行组成。例如:

2022-09-21T00:02:45 [18633]: connection opened
2022-09-21T00:02:45 [3711]: connection opened
2022-09-21T00:02:45 [61811]: connection opened
2022-09-21T00:02:45 [9957]: connection opened
2022-09-21T00:02:46 [3711]: authentication attempt
2022-09-21T00:02:46 [61811]: authentication attempt
2022-09-21T00:02:49 [3711]: user FOO authentication failure
2022-09-21T00:02:51 [18633]: authentication attempt
2022-09-21T00:02:51 [9957]: authentication attempt
2022-09-21T00:03:01 [9957]: user QOZ authentication failure
2022-09-21T00:03:02 [3711]: connection closed
2022-09-21T00:03:34 [61811]: user BAR authentication success
2022-09-21T00:03:38 [61811]: connection closed
2022-09-21T00:03:45 [18633]: user BAZ authentication success
2022-09-21T00:03:45 [18633]: connection closed
2022-09-21T00:04:11 [9957]: connection closed

我想找到所有处理成功身份验证的日志。我可以通过找到这些PID,然后再次为包含该PID的所有行发送文件来做到这一点:

for pid in $(cat log.txt | sed -En 's/.*[([0-9]+)].*success/1/p'); do
grep $pid log.txt
done

这项工作:

2022-09-21T00:02:45 [61811]: connection opened
2022-09-21T00:02:46 [61811]: authentication attempt
2022-09-21T00:03:34 [61811]: user BAR authentication success
2022-09-21T00:03:38 [61811]: connection closed
2022-09-21T00:02:45 [18633]: connection opened
2022-09-21T00:02:51 [18633]: authentication attempt
2022-09-21T00:03:45 [18633]: user BAZ authentication success
2022-09-21T00:03:45 [18633]: connection closed

但它的效率非常低,因为有很多事件,而且我正在为所有这些事件打包整个文件。在多GB文件上,这是不可撤消的。

我正在寻找另一种方法来做这件事。有没有办法(也许在awk中(做这样的事情?

  1. authentication success匹配行并提取PID
  2. 在邻域中搜索(比如匹配前后的10行(具有该PID的行,并返回所有行

许多thx

看看这是否有效:

awk -F'[][]' '/success/{a[$2]; for(k in p) if(p[k]==$2) print h[k]}
$2 in a{print}
{i=NR%13; p[i]=$2; h[i]=$0}' log.txt
  • -F'[][]'使用[]作为字段分隔符,因此$2给出PID
  • {i=NR%13; p[i]=$2; h[i]=$0}这将PID保存在数组p中,并将相应的行保存在h中(编号13决定保存了多少先前的行(
  • /success/{a[$2]; for(k in p) if(p[k]==$2) print h[k]}当找到新的成功PID时,将该PID保存在数组a中,并根据数组ph中先前保存的数据打印匹配结果
  • $2 in a{print}这将打印从当前行开始具有成功PID的行

我建议查看grep的上下文行控制,更准确地说,使用--context=NUM选项进行预处理,这应该允许您提取文本文件的有趣子集,从而提供更小、更易于处理的文件。

考虑以下简单示例,让file.txt内容为

Able
Baker
Charlie
Charlie
Dog
Easy
Fox

然后

grep --context=1 'Charlie' file.txt

给出输出

Baker
Charlie
Charlie
Dog

正如你所看到的,前后各有一行。

(在GNU grep 3.1中测试(

考虑这样的东西:

$ sort -k2,2 -k1,1 file |
awk '
$2 != prev { if (rec ~ /success/) print rec; rec=""; prev=$2 }
{ rec = rec $0 ORS }
END { if (rec ~ /success/) print rec }
'
2022-09-21T00:02:45 [18633]: connection opened
2022-09-21T00:02:51 [18633]: authentication attempt
2022-09-21T00:03:45 [18633]: connection closed
2022-09-21T00:03:45 [18633]: user BAZ authentication success
2022-09-21T00:02:45 [61811]: connection opened
2022-09-21T00:02:46 [61811]: authentication attempt
2022-09-21T00:03:34 [61811]: user BAR authentication success
2022-09-21T00:03:38 [61811]: connection closed

或者,如果您希望输出按成功行的时间戳而不是PID排序,您可以这样做:

sort -k2,2 -k1,1 file |
awk -v OFS='t' '
$2 != prev { prt(); numLines=0; time=""; prev=$2 }
/success/ { time = $1 }
{ rec[++numLines] = $0 }
END { prt() }
function prt(    i) {
if (time) {
for (i=1; i<=numLines; i++) {
print time, prev, rec[i]
}
}
}
' |
sort -k1,1 -k2,2 |
cut -f2-
2022-09-21T00:02:45 [61811]: connection opened
2022-09-21T00:02:46 [61811]: authentication attempt
2022-09-21T00:03:34 [61811]: user BAR authentication success
2022-09-21T00:03:38 [61811]: connection closed
2022-09-21T00:02:45 [18633]: connection opened
2022-09-21T00:02:51 [18633]: authentication attempt
2022-09-21T00:03:45 [18633]: connection closed
2022-09-21T00:03:45 [18633]: user BAZ authentication success

相关内容

最新更新