在模式的任一端提取多个行,这些行由标识符包围

时间:2014-07-17 22:50:27

标签: regex shell awk sed grep

我正在尝试从日志文件中提取特定事件的跟踪。为了找到相关的事件,我寻找$ PATTERN $。为了提取事件的完整痕迹,我希望在由$ SEPARATOR $

包围的模式的任一端提取线条。

例如,如果日志文件的内容是

Line1
Line2
SEP
Line3
Line4
Name=PATTERN
Line5
SEP
Line 6
...

我想提取

SEP
Line3
Line4
Name=PATTERN
Line5
SEP

我尝试使用sed并使其适用于单行匹配,如下所示:

echo "randomStringSEPrandomPATTERNrandomSEPrandom" | sed -n 's/^.*\(SEP.*PATTERN.*SEP\).*/\1/p'

返回SEPrandomPATTERNrandomSEP

如何为多行扩展它的任何帮助将非常感激。感谢。

3 个答案:

答案 0 :(得分:3)

sed这不是一项非常自然的任务。请改用awk

gawk特定版本(感谢Jotne更正):

gawk -vRS="SEP" '/PATTERN/ {print RT $0 RT}'

POSIX awk的版本。应该适用于BSD / OSX。

awk '
  /SEP/ {
    out = out $0 "\n"
    if (in_seps == 1) {
      if (pattern_found) {
        printf(out)
        pattern_found = 0
      }
      in_seps = 0
      out = ""
    } else
      in_seps = 1
    next
  }

  in_seps == 1 {
    out = out $0 "\n"
  }

  /PATTERN/ {
    pattern_found = 1
  }
'

sed脚本。使用GNU扩展T(像t但条件相反)。

sed -n '
  H               # append line to holdspace
  /SEP/ {         # if line was a separator
    x             # exchange pattspace and holdspace
    s/^SEP/&/     # check if it begins with a separator
    T             # if it doesn't, go to next line
    s/PATTERN/&/  # check if it contains the pattern
    T             # if it doesn't, go to next line
    p             # print it
  }
'

答案 1 :(得分:1)

以下awk适用于awk

的大多数版本
awk '{a[NR]=$0} s && /^SEP/ {e=NR;next} /^SEP/ {s=NR} /PATTERN/ {f=NR} END {if (f>s && f<e) for (i=s;i<=e;i++) print a[i]}' file
SEP
Line3
Line4
Name=PATTERN
Line5
SEP

工作原理

awk '
    {a[NR]=$0}              # Store all line in an array "a"
s && /^SEP/ {               # If flag "s" is true and line starts with "SEP" do
    e=NR                    # set end flag "e" to "NR"
    next}                   # and skip to next line
/^SEP/ {                    # If line starts with "SEP" do
    s=NR}                   # set start flag "s" to "NR"
/PATTERN/ {                 # If line contains "PATTERN" do
    f=NR}                   # set flag "f" to "NR"
END {                       # END section
    if (f>s && f<e)         # If "f" flag is larger than "s" flag and less than "e" flag (pattern within range) do
        for (i=s;i<=e;i++)  # Loop from "s" to "e"
            print a[i]}     # and print the array "a" from this position
    ' file

答案 2 :(得分:0)

或者我错过了目的,或者对于sed来说这是一项微不足道的任务(来自你的评论),如果喜欢你的样本但不是如果分隔符在同一行(就像你的测试)

sed -n "/${Separator}/,/${Separator}/ {
   H;g
   /\n${Separator}.*${Separator}$/ {
      s/.\(.*${pattern}.*\)/\1/p
      s/.*//;h
      }
   }" YourFile

假设分隔符不包含特殊(简化)RegEx字符/含义(不是仅包含单词内容,甚至包含字母的情况)

如果在同一行,请参阅其他sed回复