簡體   English   中英

SED,刪除圖案之間的線

[英]SED, deleting lines between the patterns

這與使用sed刪除模式之間的行(帶有模式的行除外)有關。

如果第二個模式出現兩次或更多次,我希望刪除這些行,直到最后一次出現第二個模式。

我該怎么做?

主要要認識到的是sed只能在單獨的行上運行,而不是一次在整個文件上運行,這意味着,如果沒有特殊處理,它就不能從正則表達式中獲得多行匹配。 為了立即處理整個文件,您首先必須將整個文件讀入內存。 有很多方法可以做到這一點。 其中之一是

sed '1h; 1!H; $!d; x; s/regex/replacement/' filename

其工作原理如下:

1h   # When processing the first line, copy it to the hold buffer.
1!H  # When processing a line that's not the first, append it to the hold buffer.
$!d  # When processing a line that's not the last, stop working here.
x    # If we get here, we just appended the last line to the hold buffer, so
     # swap hold buffer and pattern space. Now the whole file is in the pattern
     # space, where we can apply regexes to it.

我喜歡使用它,因為它不涉及跳轉標簽。 當涉及到某些sed(尤其是BSD sed,如* BSD和MacOS X)時,它們有些麻煩。

因此,剩下的就是制定多行正則表達式。 由於您未指定定界符模式,因此讓我假設您要刪除包含START的第一行和包含END的最后一行之間的行。 這可以用

sed '1h; 1!H; $!d; x; s/\(START[^\n]*\).*\(\n[^\n]*END\)/\1\2/' filename

正則表達式不包含任何引人注目的內容; 通常,您必須注意在正確的位置使用[^\\n] ,以避免貪婪地匹配行尾之外的內容。

請注意,這僅在文件足夠小以至於可以完全讀入內存時才起作用。 如果不是這種情況,我的建議是使用awk在文件上進行兩次傳遞:

awk 'NR == FNR && /START/ && !start { start = NR } NR == FNR && /END/ { end = NR } NR != FNR && (FNR <= start || FNR >= end)' filename filename

它的工作方式如下:由於filename兩次傳遞給awk ,因此awk將處理該文件兩次。 NR是總記錄(默認為行)數, FNR是到目前為止從當前文件讀取的記錄數。 在文件的第一遍中, NRFNR相等,但之后不相等。 所以:

# If this is the first pass over the file, the line matches the start pattern,
# and the start marker hasn't been set yet, set the start marker
NR == FNR && /START/ && !start { start = NR }

# If this is the first pass over the file and the line matches the end line,
# set the end marker to the current line (this means that the end marker will
# always identify the last occurrence of the end pattern that was seen so far)
NR == FNR && /END/             { end   = NR }

# In the second pass, print those lines whose number is less than or equal to
# the start marker or greater than or equal to the end marker.
NR != FNR && (FNR <= start || FNR >= end)

要跟蹤Wintermute的答案,如果您找到了一個匹配的塊,則可以一路刪除它,這樣就不必將整個文件保留在內存中:

sed '/^START$/{:a;N;/.*\nEND$/d;ba}'

(對不起,我會回答溫特姆特的回答,但顯然,我仍然需要50點聲望才能獲得該特權)

沒有示例輸入,因此猜測示例文件和模式/ line3 /和/ line6 /。

line1 #keep - up to 1st pattern line3 - including
line2 #keep
line3 #keep
line4 #delete up to last occurence of line6
line5
line6a
line7
line6b
line8 #delete
line6c #keep - the last line6
line9  #keep
line10 #keep

沒有任何黑暗的voo-doo,但是效率低下的方法可能是:

(sed -n '1,/line3/p' file; tail -r file | sed -n '1,/line6/p' | tail -r) > file2

file2將包含:

line1
line2
line3
line6c
line9
line10

說明:

sed -n '1,/line3/p' file; # prints line 1 up to pattern (included)

tail -r file | sed -n '1,/line6/p' | tail -r
#reverse the file
#print the lines up to pattern2
#reverse the result

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM