提取与规则匹配的特定集合行

提取与规则匹配的特定集合行

我有一个大文件,其日志如下所示。大约有 30000 个此类事件被记录。我需要提取以RINGINGand CLOSE(包含)开头并且不包含 的那些行30 30

要求是:

在下面看到的两个实例中,我只需要保留实例 2。实例 1 需要完全删除(它们构成了文件的大部分)

实例1:

313782 Aug 19 18:37:04.925: <DATA>  RINGING|254|01136097645|5950|$hostIp|$size  |$data
313783 Aug 19 18:37:05.262: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313784 Aug 19 18:37:09.028: <DATA>  OUT  |254|01136097645|5950|$hostIp|2 bytes  |30 93
313785 Aug 19 18:37:09.705: <DATA>  IN   |254|01136097645|5950|$hostIp|4 bytes  |30 73 F9 F8
313786 Aug 19 18:37:18.532: <DATA>  IN   |254|01136097645|5950|$hostIp|336 bytes  |30 10 60 00 06 00 00 6F 12 00                                                                                 ...
313787 Aug 19 18:37:19.485: <DATA>  OUT  |254|01136097645|5950|$hostIp|133 bytes  |30 30 60 00 00 00 06 6F 12 10                                                                                 ...
313788 Aug 19 18:37:20.898: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313789 Aug 19 18:37:22.006: <DATA>  CLOSE|254|01136097645|5950|$hostIp|$size  |$data

实例2:

(带有 30 30 的行不存在)

313782 Aug 19 18:37:04.925: <DATA>  RINGING|254|01136097645|5950|$hostIp|$size  |$data
313783 Aug 19 18:37:05.262: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313784 Aug 19 18:37:09.028: <DATA>  OUT  |254|01136097645|5950|$hostIp|2 bytes  |30 93
313785 Aug 19 18:37:09.705: <DATA>  IN   |254|01136097645|5950|$hostIp|4 bytes  |30 73 F9 F8
313786 Aug 19 18:37:18.532: <DATA>  IN   |254|01136097645|5950|$hostIp|336 bytes  |30 10 60 00 06 00 00 6F 12 00                                                                                                                                                         ...
313788 Aug 19 18:37:20.898: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313789 Aug 19 18:37:22.006: <DATA>  CLOSE|254|01136097645|5950|$hostIp|$size  |$data

答案1

假设您的日志文件名为logfile,以下是awk带有示例输出的解决方案:

$ awk '/RINGING/,/CLOSE/ {if (/30 30/){f=1}; a=a"\n"$0} f==0 && /CLOSE/ {print a} /CLOSE/{a="";f=0}' logfile    

313782 Aug 19 18:37:04.925: <DATA>  RINGING|254|01136097645|5950|$hostIp|$size  |$data
313783 Aug 19 18:37:05.262: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313784 Aug 19 18:37:09.028: <DATA>  OUT  |254|01136097645|5950|$hostIp|2 bytes  |30 93
313785 Aug 19 18:37:09.705: <DATA>  IN   |254|01136097645|5950|$hostIp|4 bytes  |30 73 F9 F8
313786 Aug 19 18:37:18.532: <DATA>  IN   |254|01136097645|5950|$hostIp|336 bytes  |30 10 60 00 06 00 00 6F 12 00
313788 Aug 19 18:37:20.898: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313789 Aug 19 18:37:22.006: <DATA>  CLOSE|254|01136097645|5950|$hostIp|$size  |$data

解释

awk依次执行每个命令:

  • /RINGING/,/CLOSE/ {if (/30 30/){f=1}; a=a"\n"$0}

    表达式/RINGING/,/CLOSE/是一个范围:它指定该命令仅适用于行组。当遇到包含文本的行时,组开始RINGING。当CLOSE遇到包含文本的行时,该组结束。对于此类组中的任何行,都会执行大括号中的命令。f如果该行包含 ,则第一个将标志设置为 1 30 30。第二个命令将当前行追加到变量中a

  • f==0 && /CLOSE/ {print a}

    这里大括号中的命令前面有两个条件并连在一起。第一个条件指定标志f为零(意味着30 30在该组中未找到),第二个条件指定该行包含文本CLOSE。如果满足这两个条件,则a打印存储在变量中的行组。

  • /CLOSE/{a="";f=0}

    最后,在包含 text 的任何行上CLOSE,变量a将重置为空字符串,并将标志f设置为零。完成此操作后,代码就准备好在下一组行(如果有)上开始。

答案2

例如,可以使用 perl 兼容的正则表达式 (PCRE)

pcregrep -M '^.*?RINGING(?(?!30 30)(?s).)+?CLOSE.*?$' file

或者

grep -zPo '^.*?RINGING(?(?!30 30)(?s).)+?CLOSE.*?$' file

或者,使用 GNU awk 更具表现力的记录分隔符

gawk -vRS="CLOSE[^\n]*\n" -vORS= '!/30 30/ {print; print RT}' file

相关内容