[sed] solange in den Patternspace einlesen, bis ein bestimmter String kommt

rumbalotte

Lieutenant
Registriert
Okt. 2010
Beiträge
668
Servus!

Ist es möglich, mit sed solange in den Patternspace einzulesen (appenden), bis ein bestimmter String kommt?

Konkret: ich habe ein XML, welches shön formatiert mit Zeichenumbrüchen etc daherkommt.
<product>
<viele>
<child>
<elemente>
</product>

Ich möchte jetzt gerne alles in den Patternspace laden, bis "</product>" kommt und dann den Patternspace ausgeben, dann gehts wieder von Vorne los.

Alternativen gehen natürlich auch (z.B. awk, von welchem ich aber überhaupt keine Ahnung habe), Vorrausetzung wäre, dass es in beide Richtungen pipen kann

Danke für alle Tips und Anregungen!
Die Lotte
 
rumbalotte schrieb:
Ich möchte jetzt gerne alles in den Patternspace laden, bis "</product>" kommt und dann den Patternspace ausgeben, dann gehts wieder von Vorne los.

Provokante Frage: Und was ist dann der Sinn Deines "sed/awk"-Scriptes, wenn es nur das wieder 1:1 ausgibt was es einliest?

Oder in anderen Worten: Du hast uns in Deinem Posting verheimlicht (weil's für Dich selbstverständlich ist, für einen Aussenstehenden aber unbekannt) was die eigentliche Arbeit Deines Scriptes sein soll ;) .

rumbalotte schrieb:
Alternativen gehen natürlich auch (z.B. awk, von welchem ich aber überhaupt keine Ahnung habe), Vorrausetzung wäre, dass es in beide Richtungen pipen kann
Mein Vorschlag wäre Perl:

Eine 1:1-Verarbeitung sieht dann z.B. so aus (nur als Beweis, daß perl in beide Richtungen pipen kann):
Code:
cat xyz.txt | perl -ne 'print $_;' | less

Eine "bessere" Lösung kann ich Dir erst geben nachdem Du Dein Geheimnis gelüftet hast...


HTH

BigNum
 
BigNum schrieb:
Provokante Frage: Und was ist dann der Sinn Deines "sed/awk"-Scriptes, wenn es nur das wieder 1:1 ausgibt was es einliest?
das ich die Daten zeilenweise in dieser Form bekomme:
<product><viele><child><elemente></product>
<product><viele><child><elemente></product>
<product><viele><child><elemente></product>
<product><viele><child><elemente></product>
<product><viele><child><elemente></product>
<product><viele><child><elemente></product>

das ist zwar inhaltlich das gleiche, aber nicht von der Struktur her...
 
rumbalotte schrieb:
das ist zwar inhaltlich das gleiche, aber nicht von der Struktur her...
Aha, das ist das Geheimnis!

Hier meine Lösung:
Code:
perl -e 'for(1..10){print"<product>\n<viele>\n<child>\n<elemente>\n</product>\n"}' | perl -ne 's/\n//g; s/<\/product>/<\/product>\n/g; print $_;'
Der erste "perl"-Ausdruck ist nur ein "Simulator" für die Eingabe (einfach durch Deinen Befehl ersetzen).
Der zweite Teil löscht zuerst die ganzen "\n" weg und fügt hinter "</product>" wieder einen ein...


HTH

BigNum
 
ich hab mal bisschen mit sed rumgetestet. Neben dem Pattern Space gibt es noch den sogenannten Hold Space und die Befehle h, H, g und G zum Kopieren/Appenden zwischen beiden Spaces.

Code:
echo -e "a\nb\n/c\nd\ne\n/c\n" | sed -n '/\/c/ !H; /\/c/ { H; g; s/\n/ /g; p; s/.*//g; h }'

Ausgabe:
Code:
# nur echo
a
b
/c
d
e
/c

#echo | sed
 a b /c
 d e /c

Der Befehl kurz erklärt:
- 'sed -n' gibt nichts mehr aus. Man muss mit p ausgeben.
- '/\/c/ !H' fügt an den Hold Space an, wenn das Pattern nicht getroffen wurde.
- '/\/c/ { H; g; s/\n/ /g; p; s/.*//g; h }' wenn das Pattern getroffen wurde:
* H fügt die aktuelle Zeile an
* g holt das Angesammelte zurück in den Pattern Space
* s ersetzt \n durch Leerzeichen
* p gibt das Ergebnis aus
* s macht den Pattern Space leer
* h überträgt in den Hold Space, um ihn zu leeren

Problem ist, dass der Hold Space zu Beginn eine leere Zeile enthält. Deshalb wird bei der Ausgabe ein Leerzeichen vorangestellt. Aber sollte für dich Ok sein, da du wahrscheinlich '\n' durch nichts ersetzt.
 
Zuletzt bearbeitet:
Vielen Dank euch beiden

@BigNum
Dir vor allem für's Augen öffnen - das Perl in beide Richtungen pipen kann, war mir klar, wende es auch oft genug an.
Aber da der aktuelle Fall die Quelle für ein PerlScript darstellt, hab ich den Wald vor Bäumen nicht gesehen; daß man da auch gerne ein 2. Perl Script mit einbeziehen kann :D

@fhtagn
Dir für dieses geile Ding da und die super ausführliche Erklärung - damit habe nicht nur ich was davon :)
 
Der Vollständigkeit halber hier noch eine Awk-Lösung:
Code:
awk '{acc = acc $0} /<\/product>/{print acc; acc = ""}'
 
Zurück
Oben