用grep解析非结构化文本文件

时间:2020-06-20 21:47:11

标签: bash parsing grep

我正在尝试分析来自MIT found here的IDS日志文件。

Summarized attack: 41.084031
 IDnum    Date       StartTime Duration Destination    Attackname insider? manual? console?success? aDump? oDump iDumpBSM? SysLogs FSListing StealthyNew? Category OS
 41.08403103/29/1999 08:18:35  00:04:07 172.016.112.050ps         out              rem     succ     aDmp   oDmp  iDmp BSM  SysLg   FSLst     Stlth   Old  llU2R 
 41.08403103/29/1999 08:19:37  00:01:56 209.154.098.104ps         out              rem     succ     aDmp   oDmp  iDmp BSM  SysLg   FSLst     Stlth   Old  llU2R 
 41.08403103/29/1999 08:29:27  00:00:43 172.016.112.050ps         out              rem     succ     aDmp   oDmp  iDmp BSM  SysLg   FSLst     Stlth   Old  llU2R 
 41.08403103/29/1999 08:40:14  00:24:26 172.016.112.050ps         out              rem     succ     aDmp   oDmp  iDmp BSM  SysLg   FSLst     Stlth   Old  llU2R 

我正在尝试编写可做两件事的命令:

  1. 首先,解析整个文件并确定以4x.xxxxx开头的不同“摘要式攻击”的数量。我通过以下方式完成了此任务: grep -o -E "Summarized attack: 4"。它返回80
  2. 第二,对于上述命令找到的每个“摘要式攻击”,解析表并确定IDnum行的数量,并返回所有“摘要”中的行总数(即攻击)攻击”。我想这个数字大约在200左右。

但是,我正在努力获取ID的数量,即该文本文件的IDnum列中的ID。

由于从技术上讲它是一个没有结构的文本文件,我该如何解析此.txt文件,就像它具有表格结构一样,以针对每个{{ 1}}紧随上述IDnum命令的搜索文本之后?

所需的输出将是上述命令发现的汇总攻击的所有IDnum的计数。我不知道计数,但我会想象一个整数输出,类似于Summarized attack的{​​{1}}返回。输出将为grep,其中80是上述grep命令在找到的所有80个“摘要式攻击”中的grep -o -E "Summarized attack: 4"列中的行所定义的“攻击”数。

如果<int>以外的其他命令更合适,那就可以。

3 个答案:

答案 0 :(得分:2)

  1. 要计算匹配数,您可以使用grep -c

    grep -cE '(^Summarized.attack:.4[0-9]\.[0-9]+$)'
    
  2. 您可以将冒号用作剪切-d的定界符
    (如果您遍历结果,则前导空格将不在乎)

    grep -oE '(^Summarized.attack:.4[0-9]\.[0-9]+$)' | cut -d: -f2
    

示例循环

   file="path/to/master-listfile-condensed.txt"
   for var in $(grep -oE '(^Summarized.attack:.4[0-9]\.[0-9]+$)' "$file" | cut -d: -f2)
     do
       printf "Summarized attacks: %s: %s\n" $var \
       $(grep -cE "(^.${var}[0-9]+/[0-9]{2}/[0-9]{4})" "$file")
   done

^行首
$行尾
.任何字节(在这种情况下为单个空格)
\.单点(转义)
[0-9]个数字
+发生一次(或多次)
{4}四次出现

答案 1 :(得分:1)

假设您的输入文件中有多个“摘要攻击:”,这可能就是您要查找的内容:

$ cat tst.awk
/^Summarized attack:/ {
    prt()
    atk = ($3 ~ /^4/ ? $3 : 0)
    cnt = 0
}
atk { cnt++ }
END {
    prt()
    print "TOTAL", tot
}

function prt() {
    if ( atk ) {
        cnt -= 2
        print atk, cnt
    }
    tot += cnt
}

$ awk -f tst.awk file

答案 2 :(得分:0)

对于您的第一部分来说,fgrep -c "Summarized attacks: 4"fgrep -F "Summarized attacks: 4"就足够了。

如果我理解您的第二部分,那么对于每个块,您都希望累加攻击行并打印总计。您可以使用

gawk '/^Summarized attack: 4/ { on=1; next} /^ 4[0-9.]*/ { if (on) ++ids; next} /^ IDnum/ {next} /^ */ {next} { on=0} END {print ids;}'< master-listfile-condensed.txt

第一条语句说,搜索({/.../)以(^开头的每一行“摘要式攻击:4”,找到后,打开“ on”标志,然后转到下一行。第二条语句说,如果这是攻击记录(即以 4开头,后跟数字字符串[*]),则检查标志;如果打开,请数数。基本上,当我们处于目标攻击记录的节中时,我们希望该标志处于打开状态。接下来的两个语句说,对于以“ IDnum”开头的所有行或所有空格(有时会插入空白行),请转到下一行;需要用它来抵消下一条语句,该语句表示,如果这不是与前面的任何一条语句匹配的行,请关闭“ on”标志。这使我们无法计算目标之外的攻击。最后,END表示最后打印总计。我得到757,这远远超出了您的范围。但我认为这是正确的。

但是,假设摘要时间戳始终在IDnum中至少重复到第一个有效数字,则更简单的方法是使用

grep -Ec '^ 4' master-listfile-condensed.txt

这意味着计算以空格4开头的所有行。在这种情况下,它可以为我们提供正确的结果。