打印开始和结束模式之间的行,但如果结束模式不存在,则不打印

打印开始和结束模式之间的行,但如果结束模式不存在,则不打印

我正在寻找两个匹配模式之间的线条。如果缺少任何开始或结束图案,则不应打印线条。

正确输入:

a
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****
b

输出将是

***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****

现在假设输入中缺少 END 模式

a
***** BEGIN *****
BASH is awesome
BASH is awesome
b

不应打印线条。

我尝试过使用 sed:

sed -n '/BEGIN/,/END/p' input

如果缺少 END 模式,它将打印直到最后一行的所有数据。

怎么解决呢?

答案1

您可以按如下方式完成此操作:

$ sed -e '
    /BEGIN/,/END/!d
    H;/BEGIN/h;/END/!d;g
' inp

它的工作原理是,对于行的开始/结束范围,它将它们存储在保存空间中。然后删除直到遇到 END 行。此时我们会想起所持有的东西。 OTW,我们什么也没得到。 HTH。

答案2

cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' | 
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac

它的工作原理是tac反转行,以便sed可以找到两个顺序中的两个分隔符。

答案3

pcregrep

pcregrep -M '(?s)BEGIN.*?END'

如果 BEGIN 和 END 位于同一行,这也适用,但不适用于以下情况:

BEGIN 1 END foo BEGIN 2
END

哪里pcregrep捕获第一个BEGIN 1 END,但不捕获第二个。

为了处理这些,awk你可以这样做:

awk '
  !inside {
    if (match($0, /^.*BEGIN/)) {
      inside = 1
      remembered = substr($0, 1, RLENGTH)
      $0 = substr($0, RLENGTH + 1)
    } else next
  }
  {
    if (match($0, /^.*END/)) {
      print remembered $0
      if (substr($0, RLENGTH+1) ~ /BEGIN/)
        remembered = ""
      else
        inside = 0
    } else
      remembered = remembered $0 ORS
  }'

在这样的输入上:

a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx

它给:

BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END

两者都需要在内存中存储从 BEGIN 到随后的 END 的所有内容。因此,如果您有一个大文件,其第一行包含 BEGIN 但没有 END,则整个文件将毫无意义地存储在内存中。

解决这个问题的唯一方法是处理文件两次,但当然,只有当输入是常规文件(例如不是管道)时才能完成。

答案4

GNU awk 方法。结果是通过在找到起始标头时设置特定变量来实现的。为了方便起见,可以缩短一些变量

$ awk '/BEGIN/{a[i++]=$0;flag=1;next};flag==1{a[i++]=$0;if($0~/END/){print_array=1; nextfile;} }; END{if(print_array) for(j=0;j<=i;j++)print a[j]}' input.txt
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****

由于缺少 END 标志,结果如预期为 null:

$ awk '/BEGIN/{a[i++]=$0;flag=1;next};flag==1{a[i++]=$0;if($0~/END/){print_array=1; nextfile;} }; END{if(print_array) for(j=0;j<=i;j++)print a[j]}' input2.txt

相关内容