Shell脚本 - 搜索多行模式并删除记录(如果匹配)

时间:2017-02-09 12:30:25

标签: bash shell awk sed

我有一个以下格式的文件。

I PRP B-PRP
am VBP B-VBP
a DT B-DT
happy JJ B-JJ
soul NN B-NN

I PRP B-PRP
am VBP B-VBP
a DT B-DT
sad JJ B-JJ
soul NN B-NN

每条记录都用空行分隔。每行有3个字段。

如果有输入我是一个快乐的灵魂我想在此文件中搜索并删除记录(如果它存在)。在此示例中,将从文件中删除记录1。由于句子分为多行,我无法弄清楚如何做到这一点。我尝试了 sed awk grep 。似乎没什么用。基本上,我无法弄清楚如何为这些命令提供模式。

sed -e '/I/,/soul/!d' filename 

大多数评论与上述类型相似,开始模式后跟结束模式。但这不符合我的情况。

如何解决这个问题?

4 个答案:

答案 0 :(得分:3)

  

如果有输入我是一个快乐的灵魂我想在此文件中搜索并删除该记录(如果它存在)。

您可以使用此awk命令:

awk -v RS= '!/^I .*\nam .*\nhappy .*\nsoul /' file

I PRP B-PRP
am VBP B-VBP
a DT B-DT
sad JJ B-JJ
soul NN B-NN

答案 1 :(得分:2)

使用AWK可以将RS(记录分隔符)设置为空,以便在空行上分割记录:

$ awk '/I.*am.*happy.*soul/' RS= input.txt
I PRP B-PRP
am VBP B-VBP
a DT B-DT
happy JJ B-JJ
soul NN B-NN

.*是两个正则表达式元字符,.表示任何字符,而*表示零次或多次。

我不确定.匹配换行符的定义有多好。

答案 2 :(得分:1)

确切的方法(订单除外,需要a[$i]=i... ("am" in a) && a["I"]<a["am"] && ...):

$ awk -v RS=  '
{
    delete a; 
    for(i=1;i<=NF;i++)  # iterate every word
        a[$i]           # and store it
} 
("I" in a) && ("am" in a) && ("a" in a) && ("happy" in a) && ("soul" in a) {next} 1
' test
I PRP B-PRP
am VBP B-VBP
a DT B-DT
happy JJ B-JJ
soul NN B-NN

编辑:测试精确单词匹配的版本以及块中单词的顺序(在本例中为记录)并接受搜索到的单词作为参数(请参阅{{1}在代码中):

s

(*)我没有测试如果在单词块中存在两次想要的单词会发生什么。最后一个位置仍然是那个词,所以去图......

答案 3 :(得分:1)

这可能适合你(GNU sed):

sed ':a;N;/^$/M!ba;/I.*am.*a.*happy.*soul/d' file

在遇到空行时,在模式空间中读取多行,匹配所需的字符串并在必要时删除。

更灵活的解决方案可能是:

sed ':a;$!{N;/^\s*$/M!ba};/\<I\>.*\<am\>.*\<a\>.*\<happy\>.*\<soul\>/d' file