2017-01-22 9 views
1

Я хочу сопоставить шаблон по нескольким строкам в сценарии оболочки. Мой вход как:Выражение соответствия между несколькими строками в сценарии оболочки

START <some data including white spaces> 
<some data including white spaces, can span across multiple lines, number of lines are variable> 
ID: n1 <some data including white spaces> 
<some data including white spaces, can span across multiple lines, number of lines are variable> 
END 

START <some data including white spaces> 
<some data including white spaces, can span across multiple lines, number of lines are variable> 
ID: n2 <some data including white spaces> 
<some data including white spaces, can span across multiple lines, number of lines are variable> 
END 

Я пытаюсь отобразить выходные данные с помощью регулярных выражений для конкретного ID только (например, n1 или n2.). Я попробовал START(.|\n)*ID: n1(.|\n)*END regex, но он также извлекает данные ID: n2. Какие изменения следует внести в regex inorder для получения данных только определенного идентификатора?

Я использую команду cat inputfile | grep 'pattern' > outputfile как команду.

Количество строк в каждом блоке, а также количество линий между START и ID: n1, ID: n1 и END может быть переменным и, следовательно, с помощью головы/хвоста не является жизнеспособным вариантом. Кроме того, я хотел бы распечатать весь блок от START до END, когда идентификатор сопоставляется.

EDIT: Я попытался с помощью Online Regex Creator и может успешно соответствовать регулярному выражению

START[\s\S][^END]*ID: n1[\s\S][^END]*END

на моем входной файл.

+0

Является ли Perl приемлемым? Легко в Perl ... – dawg

ответ

1

A GNUawk или Mawk раствор, который может обрабатывать любое количество строк, включая пустые , между парными START и END в случаях:

awk -v id='n2' -v RS='(^|\n)START |\nEND' ' 
    $0 ~ ("\nID: " id " ") { print "START " $0 "\nEND" } 
' file 

Это решение использует многосимвольное значение RS (это также регулярное выражение), которое не поддерживается в POSIX spec. Однако GNU awk и Mawk (по умолчанию awk на Ubuntu) поддерживают такие значения, тогда как BSD/macOS awk нет.

  • -v id='n2' передает значение идентификатора n2 в качестве переменной id к Awk.

  • RS='(^|\n)START |\nEND' разбивает входной сигнал на запись по линии (охватывающий) текст между маркерами START  в начале ввода/линии и маркера END после перевода строки.

  • $0 ~ ("\nID: " id " ") матчей каждой входной записи ($0) против регулярных выражений (~), который совпадает с указанным ID: перевод строки с последующим ID: , за которой следует идентификатор значения, представляющего интерес (хранится в переменной id) и в пространстве.
    Обратите внимание на то, как объединение строк в Awk работает, просто размещая ссылки на строки/переменные рядом друг с другом.

  • В случае совпадения, print "START " $0 "\nEND" печатает входную запись под рукой, bookended по START и END маркеров (которые, как разделители записей ввода, не сообщает в рамках $0).


Если линии между парными START и END вхождения все непустое (то есть, содержат, по меньшей мере, 1 символ., Даже если этот символ. Является пространством или вкладки), вот POSIX-совместимых awk решение:

awk -v id='n2' -v RS= '$0 ~ ("\nID: " id " ")' file 

Обратите внимание, что -v RS=, то есть установка разделителя входных записей (RS) в пустую строку, является идиомой awk, которая разбивает входные данные на записи на , пункты (пробеги непустых строк).

1

awk в режиме абзаца, используя два последовательных перевода строки как разделитель записей:

awk -v RS='\n\n' '/ID: n1/' file.txt 

Заменить n1 с n2, n3 ... для других.

Пример:

$ cat file.txt 
START <some data including white spaces> 
<some data including white spaces> 
ID: n1 <some data including white spaces> 
<some data including white spaces> 
END 

START <some data including white spaces> 
<some data including white spaces> 
ID: n2 <some data including white spaces> 
<some data including white spaces> 
END 

START <some data including white spaces> 
<some data including white spaces> 
ID: n3 <some data including white spaces> 
<some data including white spaces> 
END 


$ awk -v RS='\n\n' '/ID: n1/' file.txt 
START <some data including white spaces> 
<some data including white spaces> 
ID: n1 <some data including white spaces> 
<some data including white spaces> 
END 


$ awk -v RS='\n\n' '/ID: n2/' file.txt 
START <some data including white spaces> 
<some data including white spaces> 
ID: n2 <some data including white spaces> 
<some data including white spaces> 
END 


$ awk -v RS='\n\n' '/ID: n3/' file.txt 
START <some data including white spaces> 
<some data including white spaces> 
ID: n3 <some data including white spaces> 
<some data including white spaces> 
END 
+0

Количество строк между 'START' и' ID: n1', а также 'ID: n1' и' END' являются переменными. Следовательно, использование '\ n \ n' не даст требуемых результатов. –

+1

@ChintanParikh Обработка текста полностью зависит от ввода. Сделайте свой ввод точным, пожалуйста. – heemayl

+0

отредактировал вопрос. И чтобы сделать это двойным, количество строк до и после 'ID' являются переменными. Следовательно, блок данных: 'START <любые символы, охватывающие переменное число строк, включая пробелы> ID: n1 <любые символы, охватывающие переменное количество строк, включая пробелы> END'. Надеюсь, это стирает любые сомнения. –

0

В awk вы можете накопить текст между начальной модели и заканчивая рисунком, а затем проверить, что буфер для матча:

cat inputfile | awk '/^START/  { buf=$0 "\n"; flag=1; next } 
         flag   { buf=buf $0 "\n" } 
         /^END/ && flag { flag=0; if (buf ~ /ID: n1 |ID: n2 /) print buf }' 

В Perl вы можете сделать:

cat inputfile | perl -0777 -lne 'while (/(^START.*?^ID: (n\d+) .*?^END)/gms){ 
    if ($2 eq "n1" || $2 eq "n2"){ 
     print "$1\n\n"; 
    } 
}' 

В любом случае, вы можете сделать awk '{script}' inputfile или perl '{script}' inputfile, а не с помощью cat

+0

Я новичок в Perl, но при запуске кода я получаю сообщение об ошибке «String found where expected operator». –

+0

Работает ли это на примере? Обновите свой пост более подходящим примером ваших фактических данных. – dawg

+0

Единственное изменение, которое я сделал, это то, что я использовал 'cat inputfile' вместо' echo '$ txt "' –