列印開始和結束模式之間的行,但如果結束模式不存在,則不列印

列印開始和結束模式之間的行,但如果結束模式不存在,則不列印

我正在尋找兩個匹配模式之間的線條。如果缺少任何開始或結束圖案,則不應列印線條。

正確輸入:

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

相關內容