给定一个包含以下内容的文本文件:
1
2
REGEX1
3 - multiple line block
4
REGEX2
5
6
REGEX1
7 - multiple line block
REGEX2
8
9
REGEX1
10 - multiple line block
我想提取以下内容:
REGEX1
3 - multiple line block
4
REGEX1
7 - multiple line block
REGEX1
10 - multiple line block
即我想提取包括 REGEX1 和 REGEX2 之间的行,包括 REGEX1,但不是 REGEX2。
我写了一个sed
脚本: sed -n '/REGEX1/,/REGEX2/{/REGEX2/!p}' file
.
它工作正常,但是当给定这样的实例时:
1
2
REGEX2 REGEX1
3 - multiple line block
4
REGEX2
5
6
REGEX2 REGEX1
7 - multiple line block
REGEX2
8
9
REGEX2 REGEX1
10 - multiple line block
我的脚本只给我:
3 - multiple line block
4
7 - multiple line block
10 - multiple line block
我希望它输出的位置是:
REGEX2 REGEX1
3 - multiple line block
4
REGEX2 REGEX1
7 - multiple line block
REGEX2 REGEX1
10 - multiple line block
如何在不效率低下的情况下实现这一点(例如存储行号并再次浏览文件(?
罢工 1:sed 用于单个行上的简单替换,仅此而已。除了 s、g 和 p(带 -n(之外,其他任何东西都需要结构,而这些结构在 1970 年代中期 awk 发明时已经过时了。
罢工 2:你永远不应该使用范围表达式,因为它们使琐碎的任务稍微简短一些,但当任务变得更有趣时,需要完全重写或复制条件,改用标志变量。
罢工 3:sed 不支持变量,因此您无法使用标志来判断您何时进入/退出您关心的文本块。
所以 - 只需使用 awk:
$ awk '/REGEX2/{f=0} /REGEX1/{f=1} f' file
REGEX1
3 - multiple line block
4
REGEX1
7 - multiple line block
REGEX1
10 - multiple line block
在第二组输入中:
$ awk '/REGEX2/{f=0} /REGEX1/{f=1} f' file
REGEX2 REGEX1
3 - multiple line block
4
REGEX2 REGEX1
7 - multiple line block
REGEX2 REGEX1
10 - multiple line block
以上内容将在任何大小的文件上稳健高效地工作,在任何 UNIX 盒子上具有任何 awk。
有关选择文本块的更多方法,请参阅 https://stackoverflow.com/a/17914105/1745001。
你可以把原来的sed再贴一点。
sed -n '/REGEX1/,/REGEX2/{/REGEX1/{p;n};/REGEX2/!p}' file
添加/REGEX1/{p;n}
可确保 REGEX1 行打印,然后n
立即将模式空间的内容替换为下一行。
有特殊情况时,您必须重复/START/,/END/的方式,但似乎您可以通过明智地使用 n
来坚持在这里使用 sed。
但是,如果您有后续的 sed 命令,n
会烧毁您。 你可以通过管道连接到另一个 sed 调用...或使用 awk。
这可能对你有用(GNU sed(:
sed -r '/^REGEX/h;G;s/^.*((REGEX1b).*n.*2)/1/;/n.*REGEX1b/P;d' file
将REGEX
存储在保留空间中,并将其附加到以下记录中。如果正则表达式在行的附加部分中匹配,则打印前半部分,否则删除该行。
编辑:
更改为原始问题;满足以下更简单的解决方案:
sed '/^REGEX1/{:a;n;/REGEX2/!ba};d' file
但是,如果重复REGEX2 REGEX1
,则需要将其更改为:
sed ':a;/^REGEX1/{:b;n;/REGEX2/!bb;ba};d' file