如何打印开始和结束模式之间的最后一行序列?

ein*_*lum 9 grep sed awk text-processing pattern-matching

这个问题的答案:

如何grep开始和结束模式之间的行?

不关心落在匹配模式之间的多个行序列。因此,例如,sed -n '/startpattern_here/,/endpattern_here/p'将打印位于这些模式出现之间的几个行序列。

但是,假设我只想打印文件中的最后一个这样的序列。我可以用 sed 做到这一点吗?如果没有,我想可能是awk?还有什么?

笔记:

  • 您可以假设这些序列不重叠。
  • 输出中包含起始和结束模式行。
  • 对较低复杂性模式做出假设的答案也是有效的(尽管不是最佳的)。

gle*_*man 7

tac 和 awk 的结合

tac file \
| awk '
   !p && /endpattern_here/   {p = 1}
    p                        {print}
    p && /startpattern_here/ {exit}
' \
| tac
Run Code Online (Sandbox Code Playgroud)


Adm*_*Bee 6

这可能有效,假设您想要一个完整的正则表达式测试:

awk '/startpattern_here/ {buf="";f=1}
     f{buf=buf $0 "\n"}
     /endpattern_here/ {f=0; lastcomplete=buf}
     END{printf("%s",lastcomplete)}' file.txt
Run Code Online (Sandbox Code Playgroud)

这将确保仅打印完整的起止模式。

测试用例:

irrelevant
irrelevant
irrelevant
startpattern_here
relevant_but_dont_show_1
relevant_but_dont_show_1
relevant_but_dont_show_1
endpattern_here

irrelevant
irrelevant
 
startpattern_here
relevant_but_dont_show_2
relevant_but_dont_show_2
relevant_but_dont_show_2
endpattern_here

irrelevant
irrelevant

startpattern_here
relevant_and_show
relevant_and_show
relevant_and_show
endpattern_here

irrelevant
startpattern_here
incomplete_dont_show
Run Code Online (Sandbox Code Playgroud)

结果:

startpattern_here
relevant_and_show
relevant_and_show
relevant_and_show
endpattern_here
Run Code Online (Sandbox Code Playgroud)

注意如果您想抑制开始和结束模式的输出,只需交换规则/startpattern_here/ { ... }and /endpattern_here/ { ... },即首先放置“结束模式”规则,然后将“开始模式”规则放在END规则之前。


Qua*_*odo 6

使用Ex(一个 POSIX 编辑器)非常简单:

printf '%s\n' 1 '?END?' '?START?,.p' | ex -s file
Run Code Online (Sandbox Code Playgroud)
  • 1转到文件的第一行。如果END是文件的最后一行,则这是必要的。

  • ?END?为 向后寻找(环绕文件结尾)END,从而找到它在文件中的最后一次出现。

  • ?START?,.p打印从前一个START地址到当前地址的所有内容。

下面是一个使用 here-docs 而不是 的示例printf,只是为了多样性。

$ cat file
zdk
START
b12
END
kdn
START
000
111
END
START
ddd
Run Code Online (Sandbox Code Playgroud)
$ ex -s file <<EOF
> 1
> ?END?
> ?START?,.p
> EOF
START
000
111
END
Run Code Online (Sandbox Code Playgroud)


ein*_*lum 5

看来我只能使用tac

tac | sed -n '/endpattern_here/,/startpattern_here/ {p; /startpattern_here/q;}' | tac
Run Code Online (Sandbox Code Playgroud)

感谢 @glenn jackman 和 @Quasimodo 帮助我正确调用 sed。

  • `tac 文件 | sed -n '/END/,/START/p;/START/q' | tac` (2认同)

ter*_*don 2

一种方法是简单地存储每组,用下一组覆盖它,并在到达最后时打印您保留的组:

awk '{ 
        if(/startpattern_here/){
            a=1; 
            lines=$0; 
            next
        } 
        if(a){
            lines=lines"\n"$0
        } 
        if(/end_pattern/){
            a=0
        }
    } 
    END{
        print lines
    }' file
Run Code Online (Sandbox Code Playgroud)

例如,使用此测试文件:

startpattern_here
line 1
line 2
line 3
end_pattern
startpattern_here
line 1b
line 2b
line 3b
end_pattern
startpattern_here
line 1c
line 2c
line 3c
end_pattern
Run Code Online (Sandbox Code Playgroud)

我得到:

$ awk '{ if(/startpattern_here/){a=1; lines=$0; next} if(a){lines=lines"\n"$0} if(/end_pattern/){a=0}} END{print lines}' file
startpattern_here
line 1c
line 2c
line 3c
end_pattern
Run Code Online (Sandbox Code Playgroud)