Вывести строки из конфигурационных файлов только для определенного раздела - PullRequest
0 голосов
/ 02 ноября 2018

У меня есть конфигурационные файлы со многими разделами. Мне нужно собрать все строки из конкретного раздела. Раздел может появляться несколько раз в одном файле. Например:

serviceA:
   ports:
     8080
     1323
serviceB:
  test:
      MMMM
  ports:
     8081
     3123
  network:
    ddddd

Я читаю эту статью https://www.shellhacks.com/sed-awk-print-lines-between-two-patterns/ и начинаю.

Шаблон для начала раздела прост, это /ports:/, но шаблон для конца раздела не так прост, это может быть любое имя, что-то вроде [a-zA-Z]+:

Я пытаюсь использовать шаблон [a-zA-Z]+: в awk и sed.

В awk. На нем печатаются только названия разделов

awk '/ports:/,/[a-zA-Z]+:/' file
    ports:
    ports:

В сед. Он печатает от первых портов до конца файла

sed -n '/ports:/,/[a-zA-Z]+:/p' file
ports:
         8080
         1323
    serviceB:
      test:
         MMMM
      ports:
         8081
         3123
      network:
        ddddd

Я думал, что проблема в том, что шаблон [a-zA-Z]+: соответствует портам: и решил исключить порты :. ^\s*((?!ports)[a-zA-Z]+:)+ Этот шаблон работает нормально в онлайн-тестере регулярных выражений - https://regex101.com/

awk печатает от первых портов до конца файла

awk '/ports:/,/^\s*((?!ports)[a-zA-Z]+:)+/' file
ports:
             8080
             1323
        serviceB:
          test:
             MMMM
          ports:
             8081
             3123
          network:
            ddddd

В настоящее время я нашел только один случай

awk '/ports:/,/network:|serviceB:/' 
  ports:
      8080
      1323
serviceB:
  ports:
      8081
      3123
network:

Но я не знаю всех возможных названий разделов. Мне нужно универсальное решение.

Ответы [ 3 ]

0 голосов
/ 03 ноября 2018

Ваш ввод YAML , и лучше использовать синтаксический анализатор YAML для анализа этих данных.

Вы можете использовать этот код ruby для печати ports, которые находятся на втором уровне во всех верхних разделах:

ruby -ryaml -e "data=YAML::load(STDIN.read); data.each{|n|puts n.last['ports']}" < file.yml

8080 1323
8081 3123
0 голосов
/ 03 ноября 2018

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

sed '/:$/h;//d;G;/ports:$/P;d' file

Сохраните каждое имя раздела в поле для хранения, а затем удалите эту строку. Для каждой другой строки добавьте самое последнее имя раздела и, если это будет ports:, выведите только текущую строку.

0 голосов
/ 03 ноября 2018

в зависимости от вашего формата данных, что-то вроде этого должно работать

$ awk '/^[^ ]/{s=$0} /:/{p=0} /ports:/{print s; p=1} p' file

serviceA:
   ports:
     8080
     1323
serviceB:
  ports:
     8081
     3123

захват имени службы, в случае port: совпадение имени службы печати и раздела, сбросьте флаг печати p в следующем подразделе или разделе.

Если вам не нужны названия разделов

$ awk '/:/{p=0} p; /ports:/{p=1}' file

     8080
     1323
     8081
     3123
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...