Это расширение вопроса, заданного и даннгоного здесь:Найти и заменить текст в файле после совпадения с шаблоном только для первого вхождения с помощью 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'
. Измените код под свои нужды.Я использовал двойные кавычки, потому что данные содержат одинарные кавычки. Обычно нужно экранировать
$
в двойных кавычках, но здесь/
сразу после каждого$
;$/
не является допустимым именем для переменной оболочки или чего-либо, что оболочка хотела бы расширить, поэтому экранировать не нужно$
.