Dies ist eine Erweiterung der hier gestellten und beantworteten Frage:Suchen und Ersetzen von Text in einer Datei nach Übereinstimmung mit dem Muster nur beim ersten Vorkommen mit sed
Das Problem ist: Ich muss eine Suchen-und-Ersetzen-Funktion ausführen, abernurnach dem ersten Vorkommen von pattern1
gefolgt von pattern2
. Dort pattern3
muss das Suchen und Ersetzen erfolgen.
Verwenden einer Variation der Beispieldatei aus der verlinkten Frage:
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'
Ich brauche das:
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'
Die ersten beiden Server
Namen sind gleich. Das option type
ist bei jedem Server anders. Ich muss einen bestimmten Server
Namen ( Test AB
) zuordnen, dann einen option type
( sb
) und dann die Portnummer ändern.
Ich weiß nicht, wie ich mehrere Muster logisch verketten kann AND
.
Irgendwelche Tipps? sed
oder awk
Lösungen sind bevorzugt (aber für die Hardcore-Neckbeards auf der Suche nach einemrealHerausforderung, versuchen Sie es mit einer reinen BASH-Substitution. Ab BASH 5 ist in Ordnung). Danke.
Antwort1
sed
ermöglicht Ihnen, Adressbereiche in einem Formular anzugeben addr1,addr2
. Die verlinkte Antwort verwendet einen Bereich. Jetzt müssen Sie Bereiche verschachteln.
sed "
/^Server 'Test AB'$/,/^$/ {
/option type 'sb'/,/option port '/ s/option port '.*'/option port '2222'/
}" file
Das bedeutet: Von (einschließlich) einer Zeile Server 'Test AB'
bis (einschließlich) der nächsten leeren Zeile wird der darin enthaltene Code angewendet {}
.
Und der darin enthaltene Code {}
bedeutet: von (und einschließlich) einer Zeile, die enthält, option type 'sb'
bis (und einschließlich) einer Zeile, die enthält, „ option port '
Wenden Sie den s/…/…/
Befehl an“.
Und der s/…/…/
Befehl bedeutet: Ersetzen Sie in jeder Zeile das erste Vorkommen von option port '.*'
(wobei .*
gierig null oder mehr Zeichen übereinstimmt) durch option port '2222'
.
Anmerkungen:
Zum Glück gibt es leere Zeilen, mit denen wir einen Bereich beenden können. Ohne sie wären wir versucht, Bereiche von
Server
bis anzugebenServer
. Das Problem ist, dass der erste Bereich vonServer 'Test AB'
bis zum nächsten Vorkommen vonServer
das zweite Vorkommen von enthalten würdeServer 'Test AB'
; undsed
Bereiche, die vom selbenaddr1,addr2
Codestück erkannt werden, dürfen sich nicht überschneiden. TatsächlichServer 'Test AB'
würde das zweite Vorkommen von nicht als Beginn eines neuen Bereichs behandelt, sodass der darin enthaltene Code{}
für die Zeilen in diesem Abschnitt nicht ausgeführt würde.^
und$
sind Anker für den Zeilenanfang bzw. das Zeilenende. Ich habe sie mit verwendet,Server 'Test AB'
aber bewusst nicht mitoption type 'sb'
. Passen Sie den Code Ihren Bedürfnissen an.Ich habe doppelte Anführungszeichen verwendet, weil die Daten einfache Anführungszeichen enthalten. Normalerweise müssen Sie
$
in doppelten Anführungszeichen maskieren, aber hier steht/
direkt nach jedem$
;$/
ist weder ein gültiger Name für eine Shell-Variable noch irgendetwas, das die Shell erweitern möchte, also ist es nicht nötig, zu maskieren$
.