sed:选择两种模式之间的线条

时间:2017-06-20 10:34:43

标签: awk sed

给定包含以下内容的文本文件:

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

如何在没有低效率的情况下实现这一点(比如存储行号并再次浏览文件)?

3 个答案:

答案 0 :(得分:2)

罢工1:sed用于单个行上的简单替换,即全部。除了s,g和p(以及-n)之外的任何其他东西都需要构造,而这些构造在20世纪70年代中期发明awk时都已经过时了。

Strike 2:你永远不应该使用范围表达式,因为它们使得琐碎的任务变得非常简单,但是当任务变得更加有趣时需要完全重写或重复条件,而是使用标志变量。

罢工3:sed不支持变量,因此您无法使用标记来判断您何时进入/离开您关注的文本块。

所以 - 只需使用awk:

import tablib
f = open('my_file.xlsx', 'rb')
data = tablib.import_set(f.read(), format='xlsx')
data[0]

以及第二组输入:

$ 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

在任何UNIX机器上使用任何awk的任何大小的文件上面都可以健壮有效地工作。

有关选择文字块的更多方法,请参阅https://stackoverflow.com/a/17914105/1745001

答案 1 :(得分:0)

这可能适合你(GNU sed):

sed -r '/^REGEX/h;G;s/^.*((REGEX1\b).*\n.*\2)/\1/;/\n.*REGEX1\b/P;d' file

REGEX存储在保留空间中,并将其附加到以下记录中。如果正则表达式在行的附加部分匹配,那么前半部分将删除该行。

编辑:

更改原始问题;以下更简单的解决方案满足:

sed '/^REGEX1/{:a;n;/REGEX2/!ba};d' file

但是如果REGEX2 REGEX1重复,则需要将其更改为:

sed ':a;/^REGEX1/{:b;n;/REGEX2/!bb;ba};d' file

答案 2 :(得分:0)

sed -n '/REGEX1/,/REGEX2/{/REGEX1/{p;n};/REGEX2/!p}' file

添加/REGEX1/{p;n}可确保打印REGEX1行,然后n立即用下一行替换模式空间的内容。

我不喜欢你/ START /,/ END /当你/ START /和/ END /有特殊情况时你必须重复自己,但看起来你似乎坚持使用sed只需明智地使用n

但是,如果你有后续的sed命令,

n会烧掉你。你可以管道到另一个sed调用......或者使用awk。