awk匹配以aaa开头,以bbb结尾的内容,同时aaa和bbb之间还包含ccc

如果是匹配以A开头,以B结尾的内容,同时A和B之间还包含C的这种怎么做?
比如

[root@localhost ~]#cat file
aaa
grge
ddd
bbb

aaa gege
ccc
bbb

aaa gregeg
eee
bbb

  

这个中A=aaa,B=bbb,C=ccc,那么要提取出下面的……
aaa gege
ccc
bbb

 

[root@localhost ~]#awk '/aaa/{t=1}{if(t)s=length(s)?s"\n"$0:$0}/bbb/{t=0;if(s~/ccc/)print s;s=""}' file

  


第一行
pattern1{action1}
  匹配包含aaa的行,满足条件令t=1,当t=1时,if条件为真,执行s=length(s)?s"\n"$0:$0

  这里s=length(s)?s"\n"$0:$0先赋值再判断
    length(s)为真,执行s"\n"$0;s=s"\n"$0,将$0添加到s的下一行
    length(s)为假,执行$0

  man awk中length函数的解释

  length([s]) Return the length of the string s, or the length of $0 if s is not supplied.

  length(s)=length($0),即length(aaa)=3,表达式为真,此时执行第1个表达式 s"\n"$0

[root@localhost ~]#echo "aaa" | awk '{s=length(s)?s"\n"$0:$0}END{print s}'
aaa
[root@localhost ~]#echo "aaa" | awk '{s=length(s)}END{print s}'
0

 


pattern2{action2}
  匹配包含bbb的行
  s为从aaa开始的字符串
  判断字符串中是否包含ccc(正则表达式)
    满足条件,则打印s
    不满足将s变量置空

第二行
  不匹配aaa,由于第一行不满足bbb,所以t=1;
  执行{if(t)s=length(s)?s"\n"$0:$0}
    s值累加,继续将$0添加到s的下一行
  不匹配bbb,执行下一行

第三行
  不匹配aaa,继续将$0添加到s的下一行
  不匹配bbb,执行下一行

第四行
  不匹配aaa,继续将$0添加到s的下一行
  匹配bbb,执行{t=0;if(s~/ccc/)print s;s=""}
  将t置0,执行正则匹配,s是否包含ccc
    满足条件,打印s
    不满足条件,将s置空

一个循环结束(或者一个流程结束,若不满足条件则无法完成,后面的代码也就失去意义了)

改进:
length函数可以不用

awk '/aaa/{t=1}{if(t)s=s?s"\n"$0:$0}/bbb/{t=0;if(s~/ccc/)print s;s=""}' file

多种思路,感谢CU大神


awk '/^aaa/{t=1};/^bbb/{if(s~/ccc/){print s"\n"$0};s=a;t=0}t{s=s?s"\n"$0:$0}' file

awk '/^aaa/{s=$0;next};/^bbb/{if(s~/ccc/)print s"\n"$0;next}{s=s"\n"$0}' file

posted @ 2017-07-07 16:26  陈浩然201  阅读(7268)  评论(0编辑  收藏  举报