从一行打印以 x 开头的某些单词

print certain words that begins with x from one line

我想以某种方式打印单词开头的单词,例如 srcip 和 srcintf,来自 /var/log/syslog

的这一行
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 来完成它。由于显而易见的原因,它的可扩展性非常差:

cat /var/log/syslog | awk '{print ,,,,,,,,,"-----> ",}'

也不是所有的行在同一个“字段”中都有 srcip。所以有些线真的歪了。

或者系统日志消息重写器是否更适合此目的?你将如何解决这个问题?提前致谢!

我为您提供了一个灵活的 awk 答案,而不是简单的单行代码,而是一种更具编程性的方式。您的日志文件中的行通常看起来像:

key1=value1 key2=value2 key3=value3 ...

这个awk的想法是把它分解成awk中的一个数组,它是关联的,这样元素就可以被称为:

a[key1]=>value1 a[key2]=>value2 ... a[key2,"full"]=>key2=value2 ...

使用 this answer 中解释的函数,您可以编写:

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([=12=]," ","=",a) }
    { print a["date","full"],a["time","full"],a["devname","full"],a["action","full"] }
   ' file

这种方法非常灵活。在行的顺序或其他方面也没有依赖性。

注意: 上面的方法没有处理引用。因此,如果 space 出现在带引号的字符串中,它可能会把事情搞砸。

如果你有 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");
}

你可以做到:

awk -v filter="srcip,srcintf" -f filter.awk  /var/log/syslog

在您指定的过滤器中,以逗号分隔的关键字。它必须找到

注意:此脚本还假设文件的格式为:key1=value key2=value 并且值中没有 space。

$ 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

以上假定您引用的字符串不包含示例输入中所示的空格。