模式重复时如何删除两个模式之间的线(删除包括模式)
Posted
技术标签:
【中文标题】模式重复时如何删除两个模式之间的线(删除包括模式)【英文标题】:How to delete lines between two patterns(deleting inclusive of patterns) when pattern repeats 【发布时间】:2021-10-15 18:26:19 【问题描述】:我有一个包含重复模式的文件。只有当有重复的模式时,我才想删除这些模式之间的所有行。
例如,如果输入文件是:
Pattern1=File1
cat
dog
PatternEnd1
blah
blah
Pattern1=File1
fish
dog
Pattern1End
blah
blah
Pattern1=File1
tiger
dog
Pattern1End
输出应该是:
Pattern1=File1
cat
dog
PatternEnd1
blah
blah
blah
blah
我尝试使用 sed 并执行 sed '/Pattern1=File1/,/PatternEnd1/d'
但只要模式匹配,它就会删除所有内容。我想删除重复模式之间的所有内容,同时保留第一次出现。
我想在 Perl 脚本中执行此操作。
【问题讨论】:
你喜欢perl
时为什么要标记sed
和awk
【参考方案1】:
有几种方法可以做到这一点。我会使用保留空间:
sed -n '/Pattern1=File1/x;/^$/!p;d;;/Pattern1End/n;h;d;;H'
如果您遇到Pattern1=File1
,请打印保留空间中的任何内容(如果有的话)并继续。如果您遇到Pattern1End
,请抓住下一行并将其存储在保留空间中,覆盖那里的内容。否则,请收集您在暂存空间中阅读的任何内容。
【讨论】:
嗨,抱歉,我拼错了结束模式。 Pattern1=File1..PatternEnd1 是重复模式。只有第一次出现的应该被保留,重复出现的应该被删除。谢谢。【参考方案2】:在 Perl 中,您可以使用 flip-flop operator。例如:
perl -lne 'if (/^Pattern1=File1$/ .. /^Pattern1End$/)
print if !$flag else $flag=1; print' file
【讨论】:
感谢您的意见。但是,此代码正在删除所有重复项,我想保留其中一个并删除所有重复的谢谢 我使用您提供的输入对其进行了测试(在将PatternEnd1
更改为 Pattern1End
之后,因为我认为这是一个错字(?))并且它没有删除第一个.. 什么输入文件你用过吗?
我还测试了我提供的示例文件,它工作正常,但不确定为什么它不适用于我拥有的原始文件。下面 awk 实用程序提供的解决方案对我有用。非常感谢您的帮助,非常感谢。【参考方案3】:
awk '/^Pattern1=File1$/ f=f2;f1=1 !f; /^Pattern1End$/ f2=f1;f=0' file
这个方法的意思是f
直到顺序找到开始和结束模式后才能设置。 (“模式”是正则表达式吗?考虑How do I find the text that matches a pattern?)
【讨论】:
谢谢@rowboat,awk 实用程序为我创造了奇迹。但是,当我在循环中运行时,只有当我输入它正在工作的唯一文件名时,它才会给我正确的结果(很多重复项)。作为一种解决方法,对于来自循环的每个新比较,我将输出重定向到临时文件。有什么办法可以将它作为 awk 循环运行以摆脱重定向到临时文件的麻烦。提前谢谢你。 谢谢我找到了循环运行它的方法,但是如果你能解释一下逻辑,那将是非常可观的。我对 awk 完全陌生。【参考方案4】:这可能对你有用(GNU sed):
sed '/Pattern1=File1/:a;N;/Pattern1End/!ba;x;/./x;d;x;h' file
收集Pattern1=File1
和Pattern1End
之间的行。
检查保留空间以查看是否设置了标志,如果设置了则删除集合。
否则,设置标志并打印集合。
替代方案:
sed '/Pattern1=File1/,/Pattern1End/x;/Pattern1End/x;d;x;h' file
【讨论】:
以上是关于模式重复时如何删除两个模式之间的线(删除包括模式)的主要内容,如果未能解决你的问题,请参考以下文章
如何在两种模式之间打印行,包括或排他(在sed,AWK或Perl中)?