2017-02-09 12 views
1

У меня есть файл в следующем формате.Shell Script - поиск многострочного шаблона и удаление записи, если есть соответствие

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 поля.

Если есть вход Я счастливая душа Я хотел искать в этом файле и удалять запись, если она присутствует. В этом примере запись из файла будет удалена. Поскольку предложение распространяется как несколько строк, я не могу понять, как это сделать. Я попробовал sed, awk, grep. Ничто не работает. В принципе, я не могу понять, как дать шаблон для этих команд.

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

Большинство комментариев, как выше типа, начинают шаблон с последующим конечного рисунка. Но в моем случае это не сработает.

Как решить эту проблему?

ответ

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 
+0

Это работает. Благодарю. – BBHeeMAA

+0

как передать 'regex' как переменную оболочки? Это возможно? – BBHeeMAA

+0

Да. Возможно. – BBHeeMAA

2

Использование AWK можно установить RS (Record Seperator) ничего, чтобы разделить записи на пустые строки:

$ 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 

.* два регулярных выражений метасимволы, . означает любой символ, а * означает ноль или более раз.

Я не уверен, насколько хорошо определено, что . соответствует новостным линиям.

+0

Не было бы терпеть неудачу на 'III Мам ahappyp asould', затем снова я не уверен, если это имеет значение? –

+1

@JamesBrown Это верно, можно использовать границы слов, чтобы этого избежать. Но я не уверен в поддержке каждого синтаксиса, т. Е. GNU awk поддерживает '\ <' and '\>', но я не думаю, что POSIX awk. – andlrc

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 

Редактировать: Версия, которая проверяет точное совпадение слов и порядок слов в блоке (хорошо, запись в этом случае) и принимает искомые слова в качестве параметра (см s в коде):

$ awk -v ORS="\n\n" -v RS= -v s="I am a happy soul" ' 
BEGIN { 
    n=split(s,a)    # split the searched sentance to a hash 
} 
{ 
    delete b;     # delete b or block words 
    for(i=1;i<=NF;i++)  # iterate thru all words 
     b[$i]=i;    # give each word ad order (* see below) 
    for(i=1;i<=(n-1);i++)  # for each word in a see the order of block words 
     if(b[a[i]]>b[a[i+1]]) # printing at first mismatch 
      print $0 
}' test 

(*) Я не проверял, что происходит, если требуемое слово существует дважды в блоке слова. Последняя позиция остается для этого слова, так что продолжайте рисовать ...

+0

Но как удалить эту запись из файла ? Я пробовал этот код, но его не удалял. – BBHeeMAA

+0

@BBHeeMAA О, мой плохой. Все наоборот. Теперь исправлено. –

+0

Как добавить новую строку между записями при печати вывода? – BBHeeMAA

1

Это может работать для вас (GNU СЭД):

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 

 Смежные вопросы

  • Нет связанных вопросов^_^