这是关于使用sed
删除带有图案的线条之间的线条。
如果第二种模式经常出现两次或更多次,我希望删除这些行直到最后一次出现第二种模式。
我该怎么做?
答案 0 :(得分:1)
要实现的主要事情是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.
我喜欢使用这个,因为它不涉及跳转标签。一些seds(特别是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
到目前为止从当前文件读取的记录数。在文件的第一次传递中,NR
和FNR
是相同的,之后他们不会。所以:
# 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)
答案 1 :(得分:1)
要跟进Wintermute's答案,如果您找到了匹配的块,您可以在此过程中删除它,这样您就不必保留整个内存中的文件:
sed '/^START$/{:a;N;/.*\nEND$/d;ba}'
(对不起,本来会回复Wintermute的答案,但显然我仍然需要50点声望才能获得该特权)
答案 2 :(得分:0)
没有示例输入,所以猜测一个示例文件和patterns / 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