【问题标题】:read line by line with awk and parse variables使用 awk 逐行读取并解析变量
【发布时间】:2018-04-25 20:31:01
【问题描述】:

我有一个脚本可以读取日志文件并解析数据以将它们插入到 mysql 表中。

我的脚本看起来像

while read x;do
var=$(echo ${x}|cut -d+ -f1) 
var2=$(echo ${x}|cut -d_ -f3)
...
echo "$var,$var2,.." >> mysql.infile 
done<logfile

问题是日志文件有数千行并且需要几个小时......

我读到awk 更好,我试过了,但不知道解析变量的语法...

编辑: 输入是结构防火墙日志,因此它们是非常大的文件,例如

@timestamp $HOST reason="空闲超时" source-address="x.x.x.x" 源端口="19219" 目标地址="x.x.x.x" destination-port="53" service-name="dns-udp" application="DNS"....

所以我使用了很多 grep 来处理 ~60 个变量,例如

sourceaddress=$(echo ${x}|grep -P -o '.{0,0} 
source-address=\".{0,50}'|cut -d\" -f2)

如果您认为 perl 会更好,我愿意接受建议,也许会提示如何编写脚本...

【问题讨论】:

  • 我认为awk 不会在时间上给您带来任何显着的改进..
  • 使用其他语言。对于长时间的任务,我已经用 Perl 替换了 bash 脚本几次,区别是 巨大的。 Shell 很慢。
  • @sjsam 为什么不呢?见unix.stackexchange.com/questions/169716/…
  • @vessel 如果您添加示例输入(例如 3-5 行)并显示您需要附加到另一个文件的预期输出,这将有所帮助...无需复制您的全部要求,限制它说3个变量
  • @Sundeep :请注意,我在评论中使用了significant。对于较大的文件,建议使用perl。此外,您指出的链接实际上并没有在工具之间进行比较。它只是讨论实践的起起落落。

标签: bash parsing awk while-loop line


【解决方案1】:

为了回答你的问题,我假设以下游戏规则:

  • 每一行都包含各种变量
  • 可以通过不同的分隔符找到每个变量。

这为您提供了以下 awk 脚本:

awk 'BEGIN{OFS=","}
     { FS="+"; $0=$0; var=$1;
       FS="_"; $0=$0; var2=$3;
               ...
       print var1,var2,... >> "mysql.infile"
     }' logfile

它基本上做了以下事情:

  • 设置输出分隔符为,
  • 读线
  • 设置字段分隔符为+,重新解析行($0=$0)并确定第一个变量
  • 将字段分隔符设置为'_',重新解析行($0=$0)并确定第二个变量
  • ...继续所有变量
  • 将该行打印到输出文件。

【讨论】:

  • 这太好了,我快完成了,我面临的唯一问题是我需要解析来自 geoiplookup ipaddress 的变量,现在我尝试了 awk -v country="$country" , and FS="\""; $0=$0; CIP=$4; 但是如何通知每行做 country=$(geoiiplookup CIP) 我收到语法错误
  • 好的,我在stackoverflow.com/questions/20646819/…找到了答案
  • 很高兴看到您找到了解决方案。如果您使用 getline 并且有很多相同的 CIP 值,则缓冲结果以加速程序可能很有用。
  • 那么有很多相同的值,我应该如何缓冲结果...?
  • 这取决于你在做什么,但你可以有以下 awk 行(buffer[CIP]==0) { cmd="geoiiplookup "CIP; cmd | getline buffer[CIP]; close(cmd) }。这将缓冲结果,即将它存储在一个数组中。如果该值已经存在,则不再执行geoiiplookup,而只需从buffer[CIP] 中选择结果
【解决方案2】:

下面的 perl 脚本可能会有所帮助:

perl -ane '/^[^+]*/;printf "%s,",$&;/^([^_]*_){2}([^_]*){1ntf "%s\n",$+' logfile

由于$&amp; 会导致性能下降,您也可以使用/p 修饰符,如下所示:

perl -ane  '/^[^+]*/p;printf "%s,",${^MATCH};/^([^_]*_){2}([^_]*){1}_.*/;printf "%s\n",$+' logfile

有关perl 正则表达式匹配的更多信息,请参阅[ PerlDoc ]

【讨论】:

    【解决方案3】:

    如果您按顺序提取值,这样的操作会有所帮助

    $ awk -F\" '{for(i=2;i<=NF;i+=2) print $i}' file 
    
    idle Timeout
    x.x.x.x
    19219
    x.x.x.x
    53
    dns-udp
    DNS
    

    您也可以轻松更改输出格式

    $ awk -F\" -v OFS=, '{for(i=2;i<=NF;i+=2) 
                            printf "%s", $i ((i>NF-2)?ORS:OFS)}' file
    
    idle Timeout,x.x.x.x,19219,x.x.x.x,53,dns-udp,DNS
    

    【讨论】:

      猜你喜欢
      • 2014-07-11
      • 1970-01-01
      • 2014-04-28
      • 2013-04-30
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      相关资源
      最近更新 更多