【问题标题】:remove block of text between two lines based on content根据内容删除两行之间的文本块
【发布时间】:2012-12-02 14:04:50
【问题描述】:

我需要删除/过滤一个非常大的日志文件 我设法将日志文件放入以包含<----> 的行开头的文本块,以包含Content-Length: 的行结尾 现在如果此文本块包含单词REGISTER,则需要将其删除。

我找到了流动的例子:

 # sed script to delete a block if /regex/ matches inside it
 :t
 /start/,/end/ {    # For each line between these block markers..
    /end/!{         #   If we are not at the /end/ marker
       $!{          #     nor the last line of the file,
          N;        #     add the Next line to the pattern space
          bt
       }            #   and branch (loop back) to the :t label.
    }               # This line matches the /end/ marker.
    /regex/d;       # If /regex/ matches, delete the block.
 }                  # Otherwise, the block will be printed.
 #---end of script---

Russell Davies 在this 页面上撰写

但我不知道如何将其传输到单行语句以在管道中使用 我的目标是将日志文件的tail -F 通过管道传输到最终版本,以便它按分钟获得更新

【问题讨论】:

  • sed 是用于在单行上进行简单替换的出色工具,但对于其他任何事情,您都应该使用 awk,因为将来代码会更清晰并且更容易增强。请发布一些小样本输入和预期输出。

标签: bash sed awk


【解决方案1】:

试试这个:

awk '/<--|-->/{rec=""; f=1} f{rec = rec $0 ORS} /Content-Length:/{ if (f && (rec !~ "REGISTER")) printf "%s",rec; f=0}' file

如果它不符合您的要求,请提供有关您想要的更多信息以及示例输入和输出。

为了分解上面的内容,这里的每个语句都在不同的行中,并带有一些 cmets:

awk '
   /<--|-->/ {rec=""; f=1} # find the start of the record, reset the string to hold it and set a flag to indicate we've started processing a record
   f {rec = rec $0 ORS}    # append to the end of the string containing the current record
   /Content-Length:/{      # find the end of the record
      if (f && (rec !~ "REGISTER")) # print the record if it doesn't contain "REGISTER"
         printf "%s",rec
      f=0                  # clear the "found record" indicator
   }
' file

如果您的记录之间有要打印的文本,只需为未设置的“found”标志添加一个测试并调用打印当前记录的默认操作 (!f;强>)

awk '/<--|-->/{rec=""; f=1} f{rec = rec $0 ORS} !f; /Content-Length:/{ if (f && (rec !~ "REGISTER")) printf "%s",rec; f=0}' file

【讨论】:

  • 谢谢!!它完成了工作!
【解决方案2】:

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

sed '/<--\|-->/!b;:a;/Content-Length/!{$!{N;ba}};//{/REGISTER/d}' file
  • /&lt;--\|--&gt;/!b 如果一行不包含 &lt;----&gt; 打印它
  • :a;/Content-Length/!{$!{N;ba}} 不断追加行,直到遇到字符串 Content-Length 或文件结尾。
  • //{/REGISTER/d} 如果读入的行包含 Content-LengthREGISTER 则删除它/它们,否则正常打印它/它们。

【讨论】:

    【解决方案3】:

    如果我正确地得到了你需要的东西,你想过滤掉块,那就是只打印块:

    tail -f logfile | sed -n '/\(<--\|-->\)/,/Content-Length:/ p' 
    

    如果你想删除它:

    tail -f logfile | sed '/\(<--\|-->\)/,/Content-Length:/ d'
    

    【讨论】:

    • 正确,但在此缺少是否删除块的决定,如果块包含“REGISTER”,则必须将其删除,反之亦然:仅在不包含“REGISTER”时显示"
    • 对不起,我错过了。查看接受的其他解决方案是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 2013-07-31
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多