Замена совпадающего текста после двух совпадающих строк

У меня есть файл YAML, который включает в себя строфу, это выглядит так:

admin::common::passwords: alice: password: '$6$oTQhLvN/4VFJPscD$8LYwUMSFi' bob: password: '$6$JKOtLF0wHeZfIskt$W/M5.ugDS' 

Если переменная оболочки $ ACCOUNT содержит имя учетной записи (alice, bob и т. Д.), А $ YAML – это имя файла YAML, я могу добавить новую запись с sed, как это. Он вставляет новую учетную запись непосредственно в строку «admin :: common :: пароли:», поэтому я знаю, что она находится в правильной строфе:

  sed -i /'^admin::common::passwords:'/a"\ ${ACCOUNT}:\n password: '${ENCRYPTED_PASS}'" $YAML 

Я могу найти существующую учетную запись, подобную этой, с awk. Опять же, это находит строфу, затем находит учетную запись внутри этой строфы (возможно, это возможно сделать все в awk, но я недостаточно хорош для awk, и это выполнит эту работу):

  awk "BEGIN{RS=ORS="\n\n";FS=OFS="\n"}/admin::common::passwords:/" $YAML | grep -A1 "^[ ]*${ACCOUNT}:" 

Но чтобы удалить строку, лучшее, что я могу придумать, это следующее:

 sed -i "/^ ${ACCOUNT}:/,+1d" $YAML 

Которая удалит любую строку «^ alice:» в любом месте файла, независимо от того, находится ли она в строфе admin :: common :: passwords или в другом месте.

Я не могу делать никаких предположений о содержимом файла, за исключением того, что он содержит ровно одну строчку admin :: common: пароли (если это не так, то она была бы создана другой частью моего скрипта; этот бит легко).

Итак, мой вопрос заключается в следующем: как я могу улучшить этот sed, чтобы сказать « Искать» ^ $ {ACCOUNT}: « в строге admin :: common :: паролей и удалить соответствующую строку, а также строку под ней », ?

(это, конечно, не обязательно, может быть, что awk или даже Perl лучше подходят для задачи)

  • Как следить и искать в файле, проходящем через фильтр, менее
  • Согласование шаблонов по нескольким строкам
  • sed with = в качестве разделителя
  • сценарий оболочки для извлечения символов
  • Различия между sed #,%, / и |
  • Удалить строку, содержащую нечувствительность к регистру
  • Как обменивать целые html-блоки в нескольких файлах с помощью sed
  • Комментировать все строки из последней прокомментированной строки в строке с 'foo'
  • 2 Solutions collect form web for “Замена совпадающего текста после двух совпадающих строк”

     sed " /^admin::common::passwords:$/,/^[^ ].*:$/ { /^ $ACCOUNT:$/ { N;d } }" < "$YAML" 

    То есть, приложите свою строфу к строфе в разделе, совпадающем между admin::common... и следующим whatever-section:

    Остерегайтесь, что . характер, общий для имен пользователей, также является оператором регулярных выражений, поэтому john.doe будет соответствовать john.doe но, например, johnWdoe .

    Обратите внимание, что вышеуказанное не будет работать, если у вас есть два последовательных раздела admin::common::passwords а удаляемая учетная запись – во второй.

    Если, как указывает Otheus , секции работают до следующей строки с одинаковым или меньшим количеством символов пробела, а ваш раздел admin::common::passwords: могут иметь некоторые ведущие пробелы, то, вероятно, настало время перейти на другой язык, например awk :

     awk -v account="$ACCOUNT" ' match($0, /[^ ]/) && RSTART <= n {n = 0} n && NF == 1 && $1 == account ":" {getline; next} !n && /^ *admin::common::passwords:$/ { match($0, /[^ ]/) n = RSTART } {print}' < "$YAML" 

    Было бы гораздо безопаснее использовать предварительно построенные библиотеки для синтаксического анализа всего файла (например, https://stackoverflow.com/questions/1773805/how-can-i-parse-a-yaml-file ), чтобы ваш изменения, а затем повторно сохранить измененный файл. Выполнение нескольких слепых изменений текста в структурированном текстовом файле, как это, просто требует, чтобы что-то пошло не так.

    Linux и Unix - лучшая ОС в мире.