Как исключить текстовый блок awk с определенным состоянием строк в блоке

#regex #awk

Вопрос:

Я пытаюсь исключить текстовые блоки, когда возникает определенное условие.

Файлы имеют такую компоновку:

 - name: Sedan
  tags:
  - DIGIT
  - ABC
  - DEF
  - YES
- name: Combi
  tags:
  - DIGIT
  - ABC
  - DEF
  - NO
- nane: SUV
  tags:
  - DIGIT
  - DEF
  - YES
- nane: OTHER
  tags:
  - DIGIT
  - ABC
  - YES
 

Условие: ABC amp;amp; !DEF
Итак, печатайте только тот текст-блок, который будет находиться только ABC в блоке.

Это должно дать мне эту распечатку:

 - nane: OTHER
  tags:
  - DIGIT
  - ABC
  - YES
 

Моя первая попытка была чем-то вроде этого:

 awk '/^- name:/ { if (found amp;amp; value) {print value} found=value="" } { value=(value?value ORS:"")$0 } /ABC/ amp;amp; !/DEF/ { found=1 } END { if (found amp;amp; value) { print value } }' file
 

Но вышеприведенная попытка печатает каждый текстовый блок с обоими узорами!

Оба приведенных ниже решения работают, и вот как я использую их для этого для нескольких файлов:

 for i in `find /home/ -mindepth 1 -type f ! -empty`; do ln=`awk -v RS='(^|n)- ' '/- ABC(n|$)/ amp;amp; !/- DEF(n|$)/ {printf "- %sn", $0}' $i; printf $i`; echo -e $ln"n" | sed -n -e 's/^.*file: //p' | grep txt ; done
 

Спасибо

Ответ №1:

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

 awk -v RS='(^|n)- ' '/- ABC/ amp;amp; !/- DEF/ {printf "- %s", $0}' file

- nane: OTHER
  tags:
  - DIGIT
  - ABC
  - YES
 

Или, чтобы сделать это более точным:

 awk -v RS='(^|n)- ' '
/- ABC(n|$)/ amp;amp; !/- DEF(n|$)/ {printf "- %s", $0}
' file
 

Комментарии:

1. Да, это работает! Я также обновлю свой вопрос о том, как я буду использовать его в цикле for.

Ответ №2:

Обычно я не являюсь поклонником нескольких экземпляров awk/sed/grep в конвейере, но эти проблемы, похоже, подходят для этого. Во-первых, вставьте пустые строки в качестве разделителей записей. Затем отфильтруйте. Затем удалите пустые строки:

  awk '/^-/{print ""} 1' input | awk '/ABC/ amp;amp; !/DEF/' RS= | sed '/^$/d'
 

Некоторые версии awk допускают многосимвольный RS, но этот конвейер кажется достаточно простым для использования с теми реализациями awk , которые не поддерживают это расширение.

Но, похоже , лучшим решением было бы преобразовать yaml в json, затем отфильтровать с jq помощью, а затем преобразовать обратно в yaml.