【问题标题】:Sed command help to summarize similar log messagessed 命令帮助总结类似的日志信息
【发布时间】:2012-08-13 12:26:55
【问题描述】:

我正在尝试为一个应用程序制作一个日志文件摘要工具,该工具会创建许多重复的条目,只有一个不同的后缀来指示执行点。

这是一个通用版本: 包含这些内容的 text_file (infile_grocery.txt)。

milk skim fruit apple banana
milk skim fruit orange
milk skim fruit mango
milk skim fruit pomegranate
milk 2 percent fruit cherry tomato
milk 2 percent fruit peach
milk whole fruit pineapple
milk skim fruit strawberry raspberry
milk skim fruit strawberry rhubarb
milk whole fruit pineapple

我希望得到的是:

milk skim fruit apple banana, orange, mango, pomegranate
milk 2 percent fruit cherry tomato, peach
milk whole fruit pineapple
milk skim fruit strawberry raspberry, strawberry rhubarb
milk whole fruit pineapple

我目前编写的命令行是:

sed -rn "{H;x;s|^(.+) fruit ([^\n]+)\n(.*)\1 fruit (.+)$|\1 fruit \2, \4|;x}; ${x;s/^\n//;p}" infile_grocery.txt

但我得到的结果是:

milk skim fruit apple banana, mango, strawberry raspberry
milk skim fruit strawberry rhubarb
milk whole fruit pineapple

我以某种方式丢弃了输入。任何大师对如何构建这个有更好的想法?

【问题讨论】:

  • 如何识别重复行?
  • 后缀是前三个之后的单词。只有当具有相似前缀的行是连续的时,才应该进行连接。后缀也应使用逗号连接。对吗?
  • 不一定是前三个之后的词。分隔符是“水果”这个词。之前的任何内容都需要在连续的行中匹配才能使它们有资格进行修改。后面的任何内容都应该使用逗号连接到上一行的末尾。

标签: sed gnu inline-editing


【解决方案1】:

这是awk 解决方案。

awk -F fruit '
$1==x{
    printf ",%s", $2
    next
}
{
    x=$1
    printf "\n%s", $0
}
END {
    print ""
}' input.txt 

输出

milk skim fruit apple banana, orange, mango, pomegranate
milk 2 percent fruit cherry tomato, peach
milk whole fruit pineapple
milk skim fruit strawberry raspberry, strawberry rhubarb
milk whole fruit pineapple

【讨论】:

    【解决方案2】:

    这可能对你有用(GNU sed):

    sed ':a;$!N;s/^\(\(.*fruit\).*\)\n\2\(.*\)/\1,\3/;ta;P;D' file
    

    解释:

    • :a 是循环的占位符
    • $!N 追加一个换行符,后跟下一行,最后一行除外。
    • s/^\(\(.*fruit\).*\)\n\2\(.*\)/\1,\3/ 将所有内容收集到换行符到反向引用 1(又名 \1)中。在此收集从行首到包含单词fruit 的所有内容到反向引用2(又名\2)中。将匹配 \2 之后的所有内容收集到反向引用 3(又名 \3)中。将此正则表达式替换为反向引用 1,后跟一个逗号、一个空格,然后是反向引用 3。
    • ta 如果替换为真,则循环到占位符 :a
    • P 如果替换是错误的,则打印到并包括模式空间中的第一个换行符。
    • D 如果替换为假,则删除直到并包括模式空间中的第一个换行符。

    【讨论】:

    • 非常感谢!您是否愿意提供命令的演练以帮助我了解下一个问题的更好方法?
    • 在替换正则表达式的反射中,前两个 .* 应该被 [^\n]* 替换。通过防止正则表达式引擎双重回溯,这将更有效。
    【解决方案3】:
    opref=""
    nline=""
    while read line; do
      pref=`echo $line | sed 's/\(.*fruit\).*/\1/'`
      item=`echo $line | sed 's/.*fruit\s\(.*\)/\1/'`
      if [ "$opref" == "$pref" ]; then
        nline="$nline, $item"
      else
        [ "$nline" != "" ] && echo $nline
        nline=$line
      fi  
      opref=$pref
    done < input_file
    

    【讨论】:

      猜你喜欢
      • 2015-05-14
      • 2015-11-04
      • 1970-01-01
      • 2018-04-04
      • 2023-03-23
      • 2014-02-15
      • 1970-01-01
      • 1970-01-01
      • 2011-06-21
      相关资源
      最近更新 更多