Найти и заменить текст в файле можно только после совпадения двух различных шаблонов с помощью `sed` или `awk`

Найти и заменить текст в файле можно только после совпадения двух различных шаблонов с помощью `sed` или `awk`

Это расширение вопроса, заданного и даннгоного здесь:Найти и заменить текст в файле после совпадения с шаблоном только для первого вхождения с помощью sed

Проблема в следующем: мне нужно выполнить поиск и замену, нотолькопосле первого вхождения с pattern1последующим pattern2. Вот где pattern3должен произойти поиск и замена.

Используя вариант файла-образца из связанного вопроса:

Server 'Test AB'
    option type 'sa'
    option port '1234'
    option timeout '60'

Server 'Test AB'
    option type 'sb'
    option port '1234'
    option timeout '60'

Server 'Test EF'
    option type 'sa'
    option port '1234'
    option timeout '60'

Server 'Test GH'
    option type 'sa'
    option port '1234'
    option timeout '60'

Мне нужно это:

Server 'Test AB'
    option type 'sa'
    option port '1234'
    option timeout '60'

Server 'Test AB'
    option type 'sb'
    option port '9876'
    option timeout '60'

Server 'Test EF'
    option type 'sa'
    option port '1234'
    option timeout '60'

Server 'Test GH'
    option type 'sa'
    option port '1234'
    option timeout '60'

Первые два Serverимени одинаковы. option typeДля каждого сервера они разные. Мне нужно сопоставить определенное Serverимя ( Test AB), а затем option type( sb), а затем изменить номер порта.

Я не знаю, как объединить несколько шаблонов в логический AND.

Есть ли какие-нибудь советы? sedили awkрешения предпочтительны (но для хардкорных шейных бородатых, ищущихнастоящийвызов, попробуйте сделать это с помощью чистой замены BASH. BASH 5 и выше подойдет). Спасибо.

решение1

sedпозволяет вам указать диапазоны адресов в форме addr1,addr2. Связанный ответ использует диапазон. Теперь вам нужно вложить диапазоны.

sed "
/^Server 'Test AB'$/,/^$/ {
/option type 'sb'/,/option port '/ s/option port '.*'/option port '2222'/
}" file

Это означает: от (включая) строки Server 'Test AB'до (включая) следующей пустой строки применить код внутри {}.

А код внутри {}означает: от (включая) строку, содержащую, option type 'sb'до (включая) строку, содержащую option port 'применить s/…/…/команду.

А s/…/…/команда означает: в каждой строке заменить первое вхождение option port '.*'(где .*жадно соответствует нулю или более символов) на option port '2222'.

Примечания:

  • К счастью, есть пустые строки, которые мы можем использовать для завершения диапазона. Без них у нас возникло бы искушение указать диапазоны от Serverдо Server. Проблема в том, что первый диапазон от Server 'Test AB'до следующего вхождения Serverбудет включать второе вхождение Server 'Test AB'; и в sedдиапазонах, обнаруженных тем же addr1,addr2фрагментом кода, не могут перекрываться. По сути, второе вхождение Server 'Test AB'не будет рассматриваться как начало нового диапазона, поэтому код внутри {}не будет выполняться для строк в этом разделе.

  • ^и $являются якорями для начала и конца строки соответственно. Я использовал их с , Server 'Test AB'но намеренно не использовал их с option type 'sb'. Измените код под свои нужды.

  • Я использовал двойные кавычки, потому что данные содержат одинарные кавычки. Обычно нужно экранировать $в двойных кавычках, но здесь /сразу после каждого $; $/не является допустимым именем для переменной оболочки или чего-либо, что оболочка хотела бы расширить, поэтому экранировать не нужно $.

Связанный контент