Parsing 从一行打印以x开头的某些单词
我想从这行/var/log/syslog打印以srcip和srcintf开头的单词Parsing 从一行打印以x开头的某些单词,parsing,awk,syslog,Parsing,Awk,Syslog,我想从这行/var/log/syslog打印以srcip和srcintf开头的单词 Jul 21 13:13:35 some-name date=2020-07-21 time=13:13:34 devname="devicename" devid="deviceid" logid="0000000013" type="traffic" subtype="forward" level="
Jul 21 13:13:35 some-name date=2020-07-21 time=13:13:34 devname="devicename" devid="deviceid" logid="0000000013" type="traffic" subtype="forward" level="notice" vd="root" eventtime=1595330014 srcip=1.2.3.4 srcport=57324 srcintf="someinterface" srcintfrole="wan" dstip=5.6.7.8 dstport=80 dstintf="anotherinterface" dstintfrole="lan" sessionid=supersecretid proto=6 action="deny" policyid=0 policytype="policy" service="HTTP" dstcountry="Sweden" srccountry="Sweden" trandisp="noop" duration=0 sentbyte=0 rcvdbyte=0 sentpkt=0 appcat="unscanned" crscore=30 craction=131072 crlevel="high"
看起来像这样的东西
date=2020-07-21 time=13:13:34 devname="devicename" action="deny" policyid=0 srcintf="someinterface" dstintf="anotherinterface" srcip=1.2.3.4 srcport=57324 -----> dstip=5.6.7.8 dstport=80
目前我正在使用awk来做这件事。it的可扩展性非常差,原因很明显:
cat /var/log/syslog | awk '{print $5,$6,$7,$25,$26,$17,$21,$15,$16,"-----> "$19,$20}'
此外,并非所有行都在同一“字段”中具有srcip。所以有些线是倾斜的
或者系统日志消息重写器更适合于此目的?你将如何着手解决这个问题?提前谢谢 我为您提供了一个awk答案,它非常灵活,而且比简单的一行程序更具编程性。日志文件中的行通常如下所示:
key1=value1 key2=value2 key3=value3 ...
此awk中的想法是将其分解为awk中的一个关联数组,以便将元素称为:
a[key1]=>value1 a[key2]=>value2 ... a[key2,"full"]=>key2=value2 ...
使用中介绍的函数,您可以编写:
awk '
function str2map(str,fs1,fs2,map, n,tmp) {
n=split(str,map,fs1)
for (;n>0;n--) {
split(map[n],tmp,fs2);
map[tmp[1]]=tmp[2]; map[tmp[1],"full"]=map[n]
delete map[n]
}
}
{ str2map($0," ","=",a) }
{ print a["date","full"],a["time","full"],a["devname","full"],a["action","full"] }
' file
这种方法非常灵活。在行的顺序或其他方面也没有依赖关系
注意:上述方法不考虑报价。因此,如果空格出现在带引号的字符串中,它可能会把事情搞砸。如果您有
filter.awk
:
BEGIN{
split(filter,a,",");
for (i in a){
f[a[i]]=1;
}
}
{
for (i=1; i<=NF; i++) {
split($i,b,"=");
if (b[1] in f){
printf("%s ", $i);
}
}
printf("\n");
}
在您指定的过滤器中,关键字以逗号分隔。它必须找到
注意:此脚本还假设文件的格式为:key1=value key2=value
,并且值中没有空格
$ cat tst.awk
{
delete f
for (i=5; i<=NF; i++) {
split($i,tmp,/=/)
f[tmp[1]] = $i
}
print f["date"], f["time"], f["devname"], f["action"], f["policyid"], f["srcintf"], \
f["dstintf"], f["srcip"], f["srcport"], "----->", f["dstip"], f["dstport"]
}
上面假设引用的字符串不包含示例输入中所示的空格。split()的第三个参数是一个regexp,而不是字符串,因此您应该尝试使用regexp而不是字符串分隔符,以防有朝一日受到影响
split(filter,a,/,/)
和split($i,b,/=/)
来自:“第三个参数fieldpat是一个描述字符串中字段的regexp(就像FPAT是一个描述输入记录中字段的regexp)。它可以是一个regexp常量,也可以是一个字符串。”是的,真的,它以“或字符串”结尾,这是正确的,您可以在需要时在那里指定一个字符串,但是awk首先将该字符串转换为regexp,然后split()
使用它,因此当您提供一个字符串时,它会被awk解析两次,这意味着您会遇到一些额外的复杂性,例如必须在转义时加倍,因此只有在需要时才会这样做,就像把引号从shell变量中去掉一样-你可以在需要的时候这样做。顺便说一句,同样的问题只是在一个不同的问题中用不同的函数出现了-请参阅。@kvantour我添加了删除f
,谢谢。我不认为这篇文章需要它,但它不会有什么坏处,其他阅读这篇文章的人可能会从中受益。
$ cat tst.awk
{
delete f
for (i=5; i<=NF; i++) {
split($i,tmp,/=/)
f[tmp[1]] = $i
}
print f["date"], f["time"], f["devname"], f["action"], f["policyid"], f["srcintf"], \
f["dstintf"], f["srcip"], f["srcport"], "----->", f["dstip"], f["dstport"]
}
$ awk -f tst.awk file
date=2020-07-21 time=13:13:34 devname="devicename" action="deny" policyid=0 srcintf="someinterface" dstintf="anotherinterface" srcip=1.2.3.4 srcport=57324 -----> dstip=5.6.7.8 dstport=80