sed для извлечения строк, следующих шаблону начальной группы

Изменить ЗАПРОС _КОМАНДА на:

PROMPT_COMMAND='if [ $? -eq 0 ]; then counter=$((counter+1)); else counter=0; fi'

Используйте одинарные -кавычки, чтобы предотвратить преждевременное расширение $?, и используйте прямое присвоение для увеличенного значения counter.

0
16.09.2020, 15:13
5 ответов

Если вам также нужно решение Sed, это некрасиво, но должно работать.

sed -n '
  /^A/{
    N
    /\nB/!D
    N
    /\nC/!{
      s/\n//
      D
    }
    p
  }
' file

-nуказывает sed не печатать ничего, пока не будет достигнута команда p.

Если вы понимаете первый блок, вы можете понять и остальные:

  • /^A/Если пространство шаблонов начинается с A,
    • NДобавить следующую строку в пространство шаблона.
    • /\nB/!DЕсли в пространстве шаблонов нет новой строки, за которой следует B, удалите все до первой новой строки и начните заново с результирующим пространством шаблонов и без чтения каких-либо входных данных.

Один вкладыш:sed -n '/^A/{N;/\nB/!D;N;/\nC/!{s/\n//;D};p}' file

2
18.03.2021, 23:04

Следующая awkпрограмма должна работать:

awk 's==2{if (/^C/) {s=0; p=p ORS $0; print p} else {s=0}}\
     s==1{if (/^B/) {s=2; p=p ORS $0} else {s=0}}\
     s==0{if (/^A/) {s=1; p=$0}}' input.txt 

Это сохранит внутренний флаг «статуса» s, чтобы увидеть, в какой точке последовательности мы находимся (0 :начало не найдено, 1:Aнайдено, 2:Aи Bнаходится в последовательности )и накапливает текст в буфере p.

  • Если Aи Bбыли найдены, а текущая строка начинается с C, мы добавляем текущую строку в буфер и печатаем ее. Состояние сбрасывается на0
  • Если Aнайдено, и текущая строка начинается с B, мы добавляем текущую строку в буфер и устанавливаем статус2(= Aи Bнайдено)
  • Если начало еще не найдено, а текущая строка начинается с A, мы добавляем это в буфер и устанавливаем статус в 1.
1
18.03.2021, 23:04

вы можете настроить конечный автомат в sed для перехода к следующему состоянию, только если предыдущее состояние приведет вас к A -> B -> C

В противном случае отрубите голову и перезапустите.

$ sed -e '$d;/\n/d
    /^A/N;/\nB/!D
    $!N;/\nC/!D
' file
A1
B1
C1
A4
B4
C4

если у вас есть gnu grep, скомпилированный с опцией PCRE, то следующий код grep Есть другой способ.

$ grep -zoP '(?m)^A.*\nB.*\nC.*\n' file | tr -d '\0'
0
18.03.2021, 23:04

Другое решение сawk:

awk 'p2~/^A/ && p1~/^B/ && /^C/{print p2 RS p1 RS $0} {p2=p1; p1=$0}'

С perlи выделением всего ввода как одной строки:

perl -0777 -ne 'print /^A.*\nB.*\nC.*\n/mg'

С ripgrep , который поддерживает удобную опцию многострочного сопоставления-U

rg -oUN '^A.*\nB.*\nC.*'

Здесь опция -oполучает только совпадающую часть, а опция -Nпредназначена для предотвращения номеров строк в выводе

4
18.03.2021, 23:04

Это основано на многострочном пространстве шаблонов -и отбрасывает самую верхнюю -строку, как только совпадение не найдено, и затем поиск начинается заново. Линии добавляются после каждого матча. Группа считается полностью подобранной, когда все части совпадают по очереди :

.
sed '/^A/!D; /\n/!N; /\nB/!D; N; /\nC/!D'

Решение можно обобщить, чтобы оно соответствовало произвольному количеству строк, и немного больше внимания уделять изоляции поисковых терминов. Приведенный ниже скрипт будет соответствовать группе из 4 -строк (, например. A|B|A|B ), просто замените каждую букву «X» последовательной строкой:

sed '
    # If X does not begin pattern space, delete first line,
    # return to script start, read a line if none remain
    /^X/!D
    # Append next line if pattern space holds 1 line
    /\n/!N

    # If X does not begin line 2+ of pattern space, delete first line,
    # return to script start, read a line if none remain
    /\nX/!D
    # Append next line if pattern space holds < 3 lines
    /\n.*\n/!N

    # If X does not begin line 3+ of pattern space, delete first line,
    # return to script start, read a line if none remain
    /\n.*\nX/!D
    # Append next line if pattern space holds < 4 lines
    /\n.*\n.*\n/!N

    # If X does not begin line 4+ of pattern space, delete first line,
    # return to script start, read a line if none remain
    /\n.*\n.*\nX/!D

    # After here, output pattern space then discard and start again
'
1
18.03.2021, 23:04

Теги

Похожие вопросы