将分割线与awk / gawk结合使用

时间:2013-02-08 20:23:22

标签: perl sed awk gawk

如果系统超过X个字符,系统会将其包装在日志文件中。我试图从日志中提取各种数据,但首先我需要组合所有分割线,以便gawk可以将字段解析为单个记录。

例如:

2012/11/01 field1 field2 field3 field4 fi
eld5 field6 field7
2012/11/03 field1 field2 field3
2012/12/31 field1 field2 field3 field4 fi
eld5 field6 field7 field8 field9 field10 
field11 field12 field13
2013/01/10 field1 field2 field3
2013/01/11 field1 field2 field3 field4

我想返回

2012/11/01 field1 field2 field3 field4 field5 field6 field7
2012/11/03 field1 field2 field3
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11 field12 field13
2013/01/10 field1 field2 field3
2013/01/11 field1 field2 field3 field4

在我的情况下,实际的最大行长度是130.我不愿测试该长度并使用getline加入下一行,以防有一个条目长度正好为130个字符。< / p>

一旦我清理了日志文件,我也想要提取所有相关事件,其中“相关”可能涉及以下标准:

  • 'foo'在记录的任何字段中的任何位置
  • field2 〜/ bar | dtn /
  • 如果 field1 〜/ xyz | abc /&amp;&amp; field98 ==“0001”

我想知道我是否需要运行两个连续的gawk程序,或者我是否可以将所有这些组合成一个。

我是一个傻瓜新手,来自非Unix

6 个答案:

答案 0 :(得分:2)

gawk '{ gsub( "\n", "" ); printf $0 RT }
    END { print }' RS='\n[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]' input

这可以通过以下方式进行简化:

gawk --re-interval '{ gsub( "\n", "" ); printf $0 RT }
    END { print }' RS='\n[0-9]{4}/[0-9]{2}/[0-9]{2}' input

答案 1 :(得分:2)

这可能适合你(GNU sed):

sed -r ':a;$!N;\#\n[0-9]{4}/[0-9]{2}/[0-9]{2}#!{s/\n//;ta};P;D' file

答案 2 :(得分:2)

$ awk '{printf "%s%s",($1 ~ "/" ? rs : ""),$0; rs=RS} END{print ""}' file
2012/11/01 field1 field2 field3 field4 field5 field6 field7
2012/11/03 field1 field2 field3
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11  field12 field13
2013/01/10 field1 field2 field3
2013/01/11 field1 field2 field3 field4

既然我已经注意到你实际上并不想打印重组记录,那么这是另一种方法,可以更好地测试重新编译的记录(此脚本中的“s”:

$ awk 'NR>1 && $1~"/"{print s; s=""} {s=s $0} END{print s}' file

现在有了这个结构,而不是只打印s,你可以对s进行测试,例如(在第3条记录中注意“foo”):

$ cat file
2012/11/01 field1 field2 field3 field4 fi
eld5 field6 field7
2012/11/03 field1 field2 field3
2012/12/31 field1 field2 foo field4 fi
eld5 field6 field7 field8 field9 field10
field11 field12 field13
2013/01/10 field1 field2 field3
2013/01/11 field1 field2 field3 field4

$ awk '
function tst(rec,     flds,nf,i) {
   nf=split(rec,flds)
   if (rec ~ "foo") {
      print rec
      for (i=1;i<=nf;i++)
         print "\t",i,flds[i]
   }
}
NR>1 && $1~"/" { tst(s); s="" }
{ s=s $0 }
END { tst(s) }
' file
2012/12/31 field1 field2 foo field4 field5 field6 field7 field8 field9 field10 field11 field12 field13
         1 2012/12/31
         2 field1
         3 field2
         4 foo
         5 field4
         6 field5
         7 field6
         8 field7
         9 field8
         10 field9
         11 field10
         12 field11
         13 field12
         14 field13

答案 3 :(得分:1)

这是一个稍微大一点的Perl解决方案,它也处理额外的过滤(当你标记这个 perl 时):

root@virtualdeb:~# cat combine_and_filter.pl 
#!/usr/bin/perl -n 

if (m!^2\d{3}/\d{2}/\d{2} !){
    print $prevline if $prevline =~ m/field13/;
    $prevline = $_;
}else{
    chomp($prevline);
    $prevline .= $_
}


root@virtualdeb:~# perl combine_and_filter < /tmp/in.txt
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11 field12 field13

答案 4 :(得分:1)

这可能适合你:

awk --re-interval '/^[0-9]{4}\//&&s{print s;s=""}{s=s""sprintf($0)}END{print s}' file

用你的例子测试:

kent$  echo "2012/11/01 field1 field2 field3 field4 fi
eld5 field6 field7
2012/11/03 field1 field2 field3
2012/12/31 field1 field2 field3 field4 fi
eld5 field6 field7 field8 field9 field10 
field11 field12 field13
2013/01/10 field1 field2 field3
2013/01/11 field1 field2 field3 field4"|awk --re-interval '/^[0-9]{4}\//&&s{print s;s=""}{s=s""sprintf($0)}END{print s}'
2012/11/01 field1 field2 field3 field4 field5 field6 field7
2012/11/03 field1 field2 field3
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11 field12 field13
2013/01/10 field1 field2 field3
2013/01/11 field1 field2 field3 field4

答案 5 :(得分:0)

这是一个非常简短的脚本来实现这一目标。

sed '/^[[:digit:]]/ { :r N; /\n\([^[:digit:]]\)/ s:: \1:g; tr; } ' FILE

你对这种形式感到满意吗?