Intereting Posts
Выбор файлов, начинающихся с $ LETTER, или буквы позже, чем $ LETTER в алфавите Я не могу создать fstab при установке arch Когда кошка заканчивает чтение из трубы? Почему strace и ltrace вызывают EINTR? Добавление символа в любую другую текстовую строку Какие альтернативы существуют для ipset для блокировки больших наборов IP-адресов / диапазонов адресов? Как зарезервированные блоки GDT используются после изменения размера сети в файловой системе ext3 Как cat / dev / ttyUSB0 в новый файл ежедневно Имена файлов каталогов с sed с пробелами найти и конвейер grep ничего не возвращает Вывод цитат для scp Перемещение программ, скомпилированных на компьютере на другой компьютер, и устранение проблем с библиотечными зависимостями Что является преимуществом (-ами) запуска приложений в backgound? Как настроить isc-dhcp-сервер, чтобы предлагать серверы upstream DNS? Куда записывать данные, которые должны сохраняться до следующего запуска приложения?

Получить текст между шаблоном начала и конечным шаблоном на основе шаблона между шаблоном начала и конца

Я пытаюсь получить все между startStr и endStr для случая bbb . Я понимаю, как я могу получить все вхождения между startStr и endStr используя sed . Я не вижу, как я ограничил бы его только одним экземпляром, где встречается bbb .

Пример ввода:

 fff startStr aaa bbb ccc endStr xxx yyy startStr ddd endStr ddd bbb 

Требуемый вывод:

 startStr aaa bbb ccc endStr 

Это то, что у меня есть:

 $ sed -n -e '/startStr/,/endStr/ p' sample.txt startStr aaa bbb ccc endStr startStr ddd endStr 

Для первого startStrendStr содержит /bbb/ endStr :

  sed -n '/startStr/ {:n; N; /endStr/ {/\n[^\n]*bbb[^\n]*\n/ {p; q}; b}; bn}' 

или

 sed -n '/startStr/ {:n; N; /endStr/ {/\nbbb\n/ {p; q}; b}; bn}' 

если bbb не является регулярным выражением, и вам нужна именно строка (от начала до \n ).

объяснение

Для адреса /startStr/ we:

  • set label :n ;
  • прочитайте следующую строку с N ;
  • убедитесь, что он соответствует /endStr/ ;
    • если это правда, проверьте /\nbbb\n/ появление в этом блоке, который мы читаем;
      • если он присутствует, то {p; q} {p; q} для «print and quit»,
      • в противном случае do b для «бросить этот блок и начать поиск в следующем»;
  • если это не конец блока, мы переходим к :n , т.е. продолжаем чтение.

Я рекомендую pcregrep для этой работы:

 pcregrep -M 'startStr(.|\n)*?bbb(.|\n)*?endStr' sample.txt 

Опция -M позволяет сопоставлять многострочные шаблоны и *? без жадного оператора. Остальное должно быть очевидно.

Модифицированный входной образец для включения блока startStr...endStr без bbb перед сопоставлением блока

 $ cat ip.txt startStr foo bar endStr fff baz startStr aaa bbb ccc endStr xxx yyy startStr ddd endStr ddd bbb 

Решение awk

 awk '/startStr/{f=1; m=0; buf = $0; next} /bbb/ && f{m=1} f{buf = buf ORS $0} /endStr/ && f{f=0; if(m==1)print buf} ' ip.txt 
  • /startStr/{f=1; m=0; buf = $0; next} /startStr/{f=1; m=0; buf = $0; next} установить флаг, чтобы указать начало блока, очистить совпадение, инициализировать буфер и перейти к следующей строке
  • /bbb/ && f{m=1} если строка содержит bbb , установите соответствие. f используется, чтобы избежать соответствия bbb за пределами startStr...endStr
  • f{buf = buf ORS $0} пока установлен флаг, скопируйте входные строки
  • /endStr/ && f{f=0; if(m==1)print buf} /endStr/ && f{f=0; if(m==1)print buf} в конце блока, буфер печати, если совпадение найдено

как однострочный:

 $ awk '/startStr/{f=1; m=0; buf = $0; next} /bbb/ && f{m=1} f{buf = buf ORS $0} /endStr/ && f{f=0; if(m==1)print buf}' ip.txt startStr aaa bbb ccc endStr 

Более простое решение perl путем отсечения всего входного файла – предполагает, что нет таких блоков, как startStr...startStr...endStr (т. Е. EndStr для первого startStr)

 $ perl -0777 -ne '(@m) = /startStr.*?endStr\n/gs; print grep { /bbb/ } @m' ip.txt startStr aaa bbb ccc endStr 

Решение Python:

 $ ./find_bound_pattern.py < input.txt startStr aaa bbb ccc endStr 

Сам скрипт:

 #!/usr/bin/env python from __future__ import print_function import sys flag = None group = [] for line in sys.stdin: if 'startStr' == line.strip(): flag = True # mark beginning of the block group.append(line.strip()) continue if flag: # we are in a block, so record lines group.append(line.strip()) if 'endStr' == line.strip(): flag = False # reached end of block, time to check if 'bbb' in group: print('\n'.join(group)) group = [] # clear list after each block end 

То, как это работает, довольно просто: мы отмечаем начало блока переменной flag и не устанавливаем его, как только мы достигнем конца блока. Как только мы дойдем до конца блока, мы проверим, что мы записали для присутствия bbb , и распечатаем все строки. Записанный список очищается в конце каждого блока, и процесс снова повторяется, поэтому он подходит для сопоставления нескольких блоков, которые могут содержать bbb .

Логика в этом подходе проста, может быть реализована на других языках, таких как C, Java или Ruby – в зависимости от вашего сердца. Обратите внимание, что в этом случае это скорее проблема сопоставления строк, но если есть необходимость в более расширенном сопоставлении шаблонов, она также может быть реализована через re модуль.

 sed -n -e '/startStr/,/bbb/p;/bbb/,/endStr/p' /path/to/input