144

使用awksed如何选择出现在两个不同标记模式之间的线条?可能有多个部分标有这些模式。

例如:假设文件包含:

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

开始模式是abc,结束模式是mno 所以,我需要输出为:

def1
ghi1
jkl1
def2
ghi2
jkl2

我正在使用 sed 匹配模式一次:

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

有什么方法sed可以awk 重复执行,直到文件结束?

4

10 回答 10

222

必要时与标志一起使用awk以触发打印:

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

这是如何运作的?

  • /abc/匹配具有此文本的行,也匹配/mno/
  • /abc/{flag=1;next}设置找到flag文本abc的时间。然后,它跳过该行。
  • /mno/{flag=0}取消设置找到flag文本mno的时间。
  • finalflag是具有默认操作的模式,即 to print $0:如果flag等于 1,则打印该行。

有关更详细的描述和示例,以及显示或不显示模式的情况,请参阅如何选择两个模式之间的线?.

于 2013-08-01T08:29:00.913 回答
53

使用sed

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

-n选项表示默认不打印。

该模式查找包含 justabc到 just的行mno,然后执行{ ... }. 第一个动作删除该abc行;第二mno行;并p打印剩余的行。您可以根据需要放松正则表达式。abc..范围之外的任何行都mno不会打印。

于 2013-08-01T08:47:40.180 回答
20

这可能对您有用(GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

删除所有行,除了开始abc和行之间的行mno

于 2013-08-01T09:39:57.923 回答
15
sed '/^abc$/,/^mno$/!d;//d' file

打两个角色比ppotong 的好 {//!b};d

空的正斜杠//表示:“重用上次使用的正则表达式”。并且该命令的作用与更容易理解的相同:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

似乎是 POSIX

如果一个 RE 为空(即没有指定模式),sed 的行为就像在最后一个应用的命令中使用的最后一个 RE 一样(作为地址或作为替代命令的一部分)。

于 2015-07-13T09:53:43.077 回答
10

从上一个响应的链接中,为我完成的ksh在 Solaris 上运行的链接是:

sed '1,/firstmatch/d;/secondmatch/,$d'
  • 1,/firstmatch/d: 从第 1 行到第一次找到firstmatch,删除。
  • /secondmatch/,$d: 从第一次出现secondmatch到文件结束,删除。
  • 分号分隔两个命令,按顺序执行。
于 2017-07-12T16:38:10.570 回答
3

像这样的东西对我有用:

文件.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

使用:awk -f file.awk data...

编辑:O_o fedorqui 解决方案比我的更好/更漂亮。

于 2013-08-01T08:44:17.507 回答
2
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
于 2013-08-01T09:13:08.923 回答
2

Don_crissti 从Show only text between 2 matching pattern的回答?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

这比 AWK 的应用程序高效得多,请参见此处

于 2015-09-11T14:21:10.690 回答
0

我尝试使用awk在两个模式之间打印线条,而pattern2 也匹配 pattern1。并且 pattern1 线也应该被打印出来。

例如来源

package AAA
aaa
bbb
ccc
package BBB
ddd
eee
package CCC
fff
ggg
hhh
iii
package DDD
jjj

应该有一个输出

package BBB
ddd
eee

其中pattern1 是package BBB,pattern2 是package \w*。请注意,这CCC不是一个已知值,因此无法逐字匹配。

在这种情况下,@scaiawk '/abc/{a=1}/mno/{print;a=0}a' file和 @fedorqui 都不awk '/abc/{a=1} a; /mno/{a=0}' file适合我。

最后,我设法解决了awk '/package BBB/{flag=1;print;next}/package \w*/{flag=0}flag' file,哈哈

更多的努力导致awk '/package BBB/{flag=1;print;next}flag;/package \w*/{flag=0}' file, 也打印 pattern2 线,也就是说,

package BBB
ddd
eee
package CCC
于 2019-01-02T08:50:03.170 回答
0

这也可以通过对标志的逻辑操作和递增/递减操作来完成:

awk '/mno/&&--f||f||/abc/&&f++' file
于 2021-03-05T20:50:57.463 回答