与模式匹配的grep线,以及匹配前后的线,直到不同的模式

时间:2018-01-30 08:28:36

标签: awk grep

Start_pattern
abc
d End_pattern
Start_pattern
abc
d
ef
ghij 
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern
Start_pattern
abc
dhi
jklm End_pattern

期望输出:

在包含Start_pattern Search_pattern开始和结束模式的End_pattern之间打印行。

Start_pattern
abc
d
ef
ghij 
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern

在上述文件中,我想搜索"ef"并在"Strat_pattern""End_pattern"之间打印行。

  1. 已经尝试了grep -B[NUM] and -A[NUM],因为它们可能没用 搜索模式“gef”和“Start_pattern”之间的行数未知 和“End_pattern”。
  2. grepsedawk欢迎任何事情。优先考虑一个班轮。
  3. sed -n '/BEGIN/,/END/p' *用于打印Search_pattern "def"End_pattern之间的行。但我无法在Start_pattern"def"
  4. 之间打印行
  5. 多个文件出现多次出现的search_pattern

4 个答案:

答案 0 :(得分:2)

使用gawk,支持多字符RS

gawk 'BEGIN{RS=ORS="End_pattern"}/ef/' file

输出:

Start_pattern
abc
d
ef
ghij 
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern

说明:

# Split records based on the End_pattern
BEGIN{RS=ORS="End_pattern"}

# Print records that contain the search term
/ef/

顺便说一下,出于美观原因,您可能希望在输出结尾添加换行符:

gawk 'BEGIN{RS=ORS="End_pattern"}/ef/;END{printf "\n"}' file

PS:虽然上述解决方案仅适用于gawk,但也可以使用与POSIX兼容的简单awk脚本实现此目的,这意味着它适用于任何awk

awk '{b=b$0"\n"}/End_pattern/{if(b~/ef/){printf "%s",b};b=""}' file

说明:

# Append the current line plus a newline to b(uffer)
{b=b$0"\n"}

# Once End_pattern is found ...
/End_pattern/{
    # Check if the buffer contains the search term
    if(b~/ef/){
        # Print the buffer when the term was found
        printf "%s",b
    }
    # Clear the buffer
    b=""
}

awk '{b=b$0"\n"}/End_pattern/{if(b~/ef/){printf "%s",b};b=""}' file

答案 1 :(得分:2)

为了完整起见,我在此处添加sed解决方案:

sed -n '/Start_pattern/{:a;N;/End_Pattern/!ba;/ef/p}'

要理解这一点,您需要将标签和分支视为goto statements

  • 如果找到Start_pattern,请执行{...}
  • 之间的内容
  • 使用a
  • 定义标签:a
  • 将该行添加到上一条记录中。 (N
  • 如果找到End_Pattern,请不要转到标签a!ba
  • 找到End_Pattern后,执行最后一部分,声明如果完整记录包含ef,请打印记录。

答案 2 :(得分:1)

根据我在其他网站上的回答进行调整 - Get text between start pattern and end pattern based on pattern between start and end pattern

$ awk '/Start_pattern/{f=1; m=0; buf = $0; next}
       /ef/ && f{m=1}
       f{buf = buf ORS $0}
       /End_pattern/ && f{f=0; if(m==1)print buf}
      ' ip.txt
Start_pattern
abc
d
ef
ghij 
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern
  • /Start_pattern/{f=1; m=0; buf = $0; next}设置标志以指示阻止开始,清除匹配,初始化缓冲区并继续下一行
  • /ef/ && f{m=1}如果行包含ef,请设置匹配。 f用于避免在ef
  • 之外匹配Start_pattern...End_pattern
  • f{buf = buf ORS $0}只要设置了标志,就会累积输入行
  • /End_pattern/ && f{f=0; if(m==1)print buf}在块结束时,如果找到匹配则打印缓冲区

答案 3 :(得分:1)

$ cat tst.awk
/Start_pattern/ { fnd=1; buf="" }
fnd {
    buf = buf $0 ORS
    if (/End_pattern/) {
        if (buf ~ /ef/) {
            printf "%s", buf
        }
        fnd = 0
        buf = ""
    }
}

$ awk -f tst.awk file
Start_pattern
abc
d
ef
ghij
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern