首先,我了解these nice个问题。我的问题有点不同:鉴于下面的文字格式来自file1
:
Pattern 1
some text to keep
nice text here
Pattern 1
another text to keep
Pattern 1
REMOVE ME
AND ME
ME TOO PLEASE
Pattern 2
如何仅删除上一个Pattern 1
和Pattern 2
之间的文字,包括模式,以便file1
现在包含:
Pattern 1
some text to keep
nice text here
Pattern 1
another text to keep
我更喜欢用sed解决方案,但任何其他解决方案(perl,bash,awk)都可以。
答案 0 :(得分:2)
perl -ne 'if (/Pattern 1/) { print splice @buff; push @buff, $_ }
elsif (/Pattern 2/) { @buff = () }
elsif (@buff) { push @buff, $_ }
else { print }
' -- file
当您看到Pattern 1
时,开始将行推入@buff
,输出到目前为止累积的所有行。当您看到Pattern 2
时,请清除缓冲区。如果缓冲区已经启动,请将任何其他行推送到它,否则打印它(在第一个Pattern 1
之前或Pattern 2
之后的文本。
注意:未指定Pattern 2
之前Pattern 1
的行为。
答案 1 :(得分:2)
在单独的sed中,我想不出一种简单而优雅的方法。有可能使用write-only code使用sed执行此操作,但我需要一个非常好的理由来编写类似的东西。 : - )
您仍然可以将sed
与其他工具结合使用:
$ tac test.txt | sed '/^Pattern 2$/,/^Pattern 1$/d' | tac
Pattern 1
some text to keep
nice text here
Pattern 1
another text to keep
如果您的系统上没有tac
,您可以创建一个:
$ alias tac="awk '{L[i++]=\$0} END {for(j=i-1;j>=0;)print L[j--]}'"
或与主题保持一致:
$ alias tac='sed '\''1!G;h;$!d'\'
那就是说,我会在awk中这样做,就像这样:
$ awk '/Pattern 1/{printf "%s",b;b=""} {b=b $0 ORS} /Pattern 2/{b=""} END{printf "%s",b}' text.txt
Pattern 1
some text to keep
nice text here
Pattern 1
another text to keep
或拆分以便于阅读/评论:
awk '
/Pattern 1/ { # If we find the start pattern,
printf "%s",b # print the buffer (or nothing if it's empty)
b="" # and empty the buffer.
}
{ # Add the current line to a buffer, with the
b=b $0 ORS # correct output record separator.
}
/Pattern 2/ { # If we find our close pattern,
b="" # just empty the buffer.
}
END { # And at the end of the file,
printf "%s",b # print the buffer if we have one.
}' test.txt
这与hek2mgl的解决方案大致相同,但更合理地命令并使用ORS。 : - )
请注意,仅当Pattern 2
在文件中仅存在一次时,这两种解决方案才能正常运行。如果你有多个块,即包含开始和结束模式,你需要更加努力地工作。如果是这种情况,请在您的问题中提供更多详细信息。
答案 2 :(得分:1)
使用awk:
awk '
# On pattern 1 and when the buffer is not empty, flush the buffer
/Pattern 1/ && b!="" { printf "%s", b; b="" }
# Append the current line and a newline to the buffer
{ b=b""$0"\n" }
# Clean the buffer on pattern 2
/Pattern 2/ { b="" }' file
答案 3 :(得分:1)
这可能适合你(GNU sed):
sed '/Pattern 1/,${//{x;//p;x;h};//!H;$!d;x;s/.*Pattern 2[^\n]*\n\?//;/^$/d}' file
这里的一般想法是收集以Pattern 1
开头的行,然后在遇到以Pattern 1
开头的另一行时刷新这些行,或者在文件结尾处删除Pattern 1
之间的行。 1}}和Pattern 2
并打印剩下的内容。
关注包含Pattern 1
的第一行和文件结尾之间的行,正常打印所有其他行。如果一行包含Pattern 1
,则交换到保留空间,如果这些行也包含相同的正则表达式,则打印这些行,然后替换保留空间中的当前行。如果当前行不包含正则表达式,则将其附加到保留空间,如果不是文件结尾,则将其删除。在文件结尾处,交换到保留空间并删除任何行,包括包含Pattern 2
的行,并打印剩余的行。
N.B。当您的示例中包含Pattern 2
的行是文件的最后一行时,会出现一个棘手的情况。由于sed使用换行来分隔线条,因此在将线条放入图案空间并在打印之前附加它们之前将其删除。如果模式/保持空间为空,则sed将附加换行符,在这种情况下会添加虚假换行符。解决方案是删除Pattern 1
和Pattern 2
之间的任何行,包括包含Pattern 2
的行后面的任何换行符。如果还有其他行将按正常方式打印,但是如果没有后续行,则保留空间现在将为空,因为它之前必须包含一些内容,因为它现在是空的,可以安全地删除它。