如何选择两个标记图案之间的线条,这些线条可能会出现awk / sed多次

时间:2013-08-01 08:25:25

标签: shell unix sed awk pattern-matching

使用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>

sedawk有没有办法在文件结束前反复执行此操作?

10 个答案:

答案 0 :(得分:170)

使用带有标记的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
  • 最终flag是一个默认操作的模式,即print $0:如果flag等于1,则会打印该行。

有关更详细的说明和示例,以及模式显示与否的情况,请参阅How to select lines between two patterns?

答案 1 :(得分:40)

使用sed

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

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

该模式会查找仅包含abcmno的行,然后执行{ ... }中的操作。第一个操作会删除abc行;第二个是mno行;并且p打印剩余的行。您可以根据需要放松正则表达式。 <{1}} .. abc范围之外的任何行都不会被打印出来。

答案 2 :(得分:17)

这可能适合你(GNU sed):

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

删除除abcmno

之间的行之外的所有行

答案 3 :(得分:13)

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

ppotong's {//!b};d

更好地打两个角色

空的正斜杠//表示:&#34;重复使用的最后一个正则表达式&#34;。并且命令的作用与更易理解的相同:

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

seems to be POSIX

  

如果RE为空(即,未指定模式),则sed的行为应如同指定最后一个命令中使用的最后一个RE(作为地址或作为替换命令的一部分)。

答案 4 :(得分:5)

从之前的响应链接中,在Solaris上运行ksh的那个链接就是:

require(dplyr)
require(ggplot2)
bp <- ggplot(data=PlantGrowth %>% group_by(group) %>% mutate(group2=paste(group,length(group))) %>% 
ungroup(), aes(x=group, y=weight, fill=group2)) + geom_violin() +
geom_dotplot(binaxis='y', stackdir='center', dotsize=0.5, binwidth = 0.01) + 
stat_summary(fun.data = give.sample.size, geom = "text")

答案 5 :(得分:2)

perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file

答案 6 :(得分:2)

Don_crissti的答案来自Show only text between 2 matching pattern

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

比AWK的应用程序效率更高,请参阅here

答案 7 :(得分:1)

这样的事情对我有用:

file.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解决方案比我的更好/更漂亮。

答案 8 :(得分: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不是一个已知值,因此无法进行字面匹配。

在这种情况下,@ scai的awk '/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

答案 9 :(得分:0)

这也可以通过对标志进行逻辑运算和递增/递减运算来完成:

awk '/mno/&&--f||f||/abc/&&f++' file