我有一个日志,其中包含来自处理身份验证的进程的行。这种认证通常由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
中(做这样的事情?
- 用
authentication success
匹配行并提取PID - 在邻域中搜索(比如匹配前后的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
中,并根据数组p
和h
中先前保存的数据打印匹配结果$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