Esta es una extensión de la pregunta formulada y respondida aquí:Busque y reemplace texto en un archivo después de que coincida el patrón solo para la primera aparición usando sed
El problema es: necesito realizar una búsqueda y reemplazo, perosolodespués de la primera aparición de pattern1
seguido de pattern2
. Ahí es donde pattern3
debe ocurrir la búsqueda y el reemplazo.
Usando una variación del archivo de muestra de la pregunta vinculada:
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'
Necesito este:
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'
Los dos primeros Server
nombres son iguales. El option type
es diferente para cada servidor. Necesito hacer coincidir un Server
nombre específico ( Test AB
), luego un option type
( sb
), y luego cambiar el número de puerto.
No sé cómo hacer que varios patrones se concatenen de forma lógica AND
.
¿Algun consejo? sed
o awk
se prefieren soluciones (pero para los barbudos incondicionales que buscan unarealdesafío, intente hacerlo con sustitución BASH pura. BASH 5 en adelante está bien). Gracias.
Respuesta1
sed
le permite especificar rangos de direcciones en un formulario addr1,addr2
. La respuesta vinculada utiliza un rango. Ahora necesitas anidar rangos.
sed "
/^Server 'Test AB'$/,/^$/ {
/option type 'sb'/,/option port '/ s/option port '.*'/option port '2222'/
}" file
Significa: desde (e incluyendo) una línea hasta Server 'Test AB'
(e incluyendo) la siguiente línea vacía, aplique el código dentro {}
.
Y el código interior {}
significa: desde (e incluyendo) una línea que contiene option type 'sb'
hasta (e incluyendo) una línea que contiene option port '
aplicar el s/…/…/
comando.
Y el s/…/…/
comando significa: en cada línea reemplace la primera aparición de option port '.*'
(donde .*
coincide con avidez cero o más caracteres) con option port '2222'
.
Notas:
Es una suerte que haya líneas vacías que podamos usar para finalizar un rango. Sin ellos estaríamos tentados a especificar rangos desde
Server
hastaServer
. El problema es que el primer rango desdeServer 'Test AB'
hasta la siguiente aparición deServer
incluiría la segunda aparición deServer 'Test AB'
; y ensed
los rangos detectados por el mismoaddr1,addr2
código no se pueden superponer. De hecho, la segunda aparición deServer 'Test AB'
no se trataría como el comienzo de un nuevo rango, por lo que el código contenido{}
no se ejecutaría para las líneas de esta sección.^
y$
son anclas para el principio y el final de la línea respectivamente. Los uséServer 'Test AB'
pero deliberadamente no los uséoption type 'sb'
. Ajusta el código a tus necesidades.Usé comillas dobles porque los datos contienen comillas simples. Por lo general, es necesario escapar
$
entre comillas dobles, pero aquí tenemos/
justo después de cada$
;$/
no es un nombre válido para una variable del shell ni nada que el shell quiera expandir, por lo que no es necesario escapar$
.