#begin command block
#append all lines between two addresses to hold space
sed -n -f - <<\SCRIPT file.xml
\|<tag1>|,\|</tag1>|{ H
#at last line of search block exchange hold and pattern space
\|</tag1>|{ x
#if not conditional ; clear buffer ; branch to script end
\|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
#do work ; print result; clear buffer ; close blocks
s?*?*?;p;s/.*//;h;b}}
SCRIPT
Wenn Sie angesichts der angezeigten Daten vor der letzten Bereinigungszeile die oben genannten Schritte ausführen, sollten Sie mit einem sed
Musterbereich arbeiten, der wie folgt aussieht:
^\n<tag1>\n<tag2>foo</tag2>\n</tag1>$
Sie können Ihren Musterbereich jederzeit mit l
ook ausdrucken . Sie können dann \n
Zeichen adressieren .
sed l <file
Zeigt Ihnen, dass jede Zeile sed
sie in der Phase verarbeitet, in der sie l
aufgerufen wird.
Also habe ich es gerade getestet und es brauchte noch eines \backslash
nach dem ,comma
in der ersten Zeile, aber ansonsten funktioniert es so wie es ist. Hier habe ich es in ein _sed_function
Feld eingefügt, damit ich es in dieser Antwort leicht zu Demonstrationszwecken aufrufen kann: (funktioniert mit eingeschlossenen Kommentaren, wird hier jedoch der Kürze halber entfernt)
_sed_function() { sed -n -f /dev/fd/3
} 3<<\SCRIPT <<\FILE
\|<tag1>|,\|</tag1>|{ H
\|</tag1>|{ x
\|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
s?*?*?;p;s/.*//;h;b}}
#END
SCRIPT
<tag1>
<tag2>bar</tag2>
</tag1>
<tag1>
<tag2>foo</tag2>
</tag1>
FILE
_sed_function
#OUTPUT#
<tag1>
<tag2>foo</tag2>
</tag1>
Jetzt wechseln wir das p
für ein, l
damit wir sehen können, womit wir arbeiten, während wir unser Skript entwickeln, und entfernen die Nicht-Op-Demo, s?
so dass die letzte Zeile von uns sed 3<<\SCRIPT
einfach so aussieht:
l;s/.*//;h;b}}
Dann werde ich es wieder ausführen:
_sed_function
#OUTPUT#
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$
In Ordnung! Ich hatte also Recht - das ist ein gutes Gefühl. Mischen wir jetzt unseren l
Blick, um die Linien zu sehen, die er zieht, aber löscht. Wir werden unseren Strom entfernen l
und einen hinzufügen, !{block}
damit es so aussieht:
!{l;s/.*//;h;b}
_sed_function
#OUTPUT#
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$
So sieht es aus, kurz bevor wir es auslöschen.
Eine letzte Sache, die ich Ihnen zeigen möchte, ist der H
alte Raum, während wir ihn aufbauen. Es gibt einige Schlüsselkonzepte, die ich hoffentlich demonstrieren kann. Also entferne ich den letzten l
Blick wieder und ändere die erste Zeile, um H
am Ende einen Blick in den alten Raum zu werfen :
{ H ; x ; l ; x
_sed_function
#OUTPUT#
\n<tag1>$
\n<tag1>\n <tag2>bar</tag2>$
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$
\n<tag1>$
\n<tag1>\n <tag2>foo</tag2>$
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$
H
Der alte Raum überlebt Linienzyklen - daher der Name. Was die Leute oft stolpern - ok, worauf ich oft stolpere - ist, dass es gelöscht werden muss, nachdem Sie es benutzt haben. In diesem Fall x
ändere ich mich nur einmal, so dass der Haltebereich zum Musterraum wird und umgekehrt, und diese Änderung überlebt auch Linienzyklen.
Der Effekt ist, dass ich meinen Haltebereich löschen muss, der früher mein Musterbereich war. Ich mache das, indem ich zuerst den aktuellen Musterraum lösche mit:
s/.*//
Das wählt einfach jedes Zeichen aus und entfernt es. Ich kann nicht verwenden, d
da dies meinen aktuellen Zeilenzyklus beenden würde und der nächste Befehl nicht abgeschlossen würde, was mein Skript so ziemlich in den Papierkorb werfen würde.
h
Dies funktioniert ähnlich wie, H
aber es überschreibt den Haltebereich. Daher habe ich meinen leeren Musterbereich über den oberen Bereich meines Haltebereichs kopiert und ihn effektiv gelöscht. Jetzt kann ich einfach:
b
aus.
Und so schreibe ich sed
Skripte.