Suchen Sie nach einer Zeichenfolge und drucken Sie alles vorher und nachher innerhalb eines Bereichs


9

Ich habe diese Datei:

sometext1{
string1
}

sometext2{
string2
string3
}

sometext3{
string4
string5
string6
}

Ich möchte diese Datei nach einer bestimmten Zeichenfolge durchsuchen und alles vor dieser Zeichenfolge bis zur Eröffnung {und alles nach dieser Zeichenfolge bis zum Abschluss drucken }. Ich habe versucht, dies mit sed zu erreichen, aber wenn ich versuche, alles im Bereich zu drucken, /{/,/string2/zum Beispiel sed, druckt dies:

sometext1{
string1
}

sometext2{
string2
sometext3{
string4
string5
string6
}

Wenn ich nach der Zeichenfolge "string2" suche, muss die Ausgabe wie folgt lauten:

sometext2{
string2
string3
}

Vielen Dank.


Nun habe ich festgestellt, dass ich die Zeilennummern der Ausgabe in der Originaldatei benötige, um sie später zu löschen. Ich habe versucht, den Befehl zu ändern, den @mikeserv ohne Glück geliefert hat. Ich bin etwas verwirrt mit der Haltefunktion von sed.
Rodrigo

Nun, meine Güte, Rodrigo, das hast du niemandem außer dir selbst gesagt. es kann gemacht werden, aber es ist am besten so gemacht grep -n '' <infile | sed .... Die sedBefehle müssen geändert werden. speziell die /Adressbits /, die nach ^Top-of-Line-Ankern suchen . Wenn Sie also meine Antwort verwenden würden, könnten Sie wahrscheinlich Folgendes tun : grep -n '' | sed 'H;/{$/h;/^[^:]*:}/x;/{\n.*PATTERN/!d'. Allen Ausgabezeilen werden die Zeilennummern der Originaldatei vorangestellt, gefolgt von einem Doppelpunkt wie 1:sometext1{\n2:string1usw. sedfiltert nur das, was zuvor gefiltert wurde, außer dass jede Ausgabezeile mit einer Nummer geöffnet wird.
Mikesserv

Antworten:


9

Hier sind zwei Befehle. Wenn Sie einen Befehl wünschen, der bis zur letzten .*{$Zeile in einer Sequenz gekürzt wird (wie bei @don_crissti ed) , können Sie Folgendes tun:

sed 'H;/{$/h;/^}/x;/{\n.*PATTERN/!d'

... das funktioniert, indem jede Zeile nach Heinem \nEwline-Zeichen an das alte Leerzeichen angehängt wird, das halte Leerzeichen für jede übereinstimmende Zeile überschrieben {$wird und halte und Muster-Leerzeichen für jede übereinstimmende Zeile ausgetauscht werden ^}- und dadurch der Puffer geleert wird.

Es werden nur Zeilen gedruckt, die mit einer {dann einer \newline und dann PATTERNirgendwann übereinstimmen - und das geschieht immer nur unmittelbar nach einem Pufferwechsel.

Es entfernt alle Zeilen in einer Reihe von {$Übereinstimmungen bis zur letzten in der Sequenz, aber Sie können alle diese einschließlich erhalten, wie:

sed '/PATTERN.*\n/p;//g;/{$/,/^}/H;//x;D'

Dabei werden Muster und halte Leerzeichen für jede ...{$.*^}.*Sequenz vertauscht, alle Zeilen innerhalb der Sequenz nach Heinem \nEwline-Zeichen an das alte Leerzeichen angehängt und für jeden Zeilenzyklus Dbis zum ersten vorkommenden \nEwline-Zeichen im Musterraum gelöscht, bevor erneut mit dem verbleibenden Zeichen begonnen wird.

Natürlich wird \nim Musterbereich nur dann eine neue Zeile angezeigt, wenn eine Eingabezeile übereinstimmt ^}- das Ende Ihres Bereichs - und wenn das Skript bei einer anderen Gelegenheit erneut ausgeführt wird, wird nur die nächste Eingabezeile wie gewohnt eingezogen.

Wenn PATTERNes sich im selben Musterbereich wie eine \nEwline befindet, wird das Los gedruckt, bevor es ^}erneut überschrieben wird (damit der Bereich beendet und der Puffer geleert werden kann) .

Angesichts dieser Eingabedatei (danke don) :

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
}

Die ersten Drucke:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

...und der zweite...

sometext2{
PATTERN
string3
}
Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

@don_crissti - Ich weiß nicht. Es begrenzt nur die Reihenfolge für eine Zeile, die mit beginnt }. Dies könnte von Vorteil sein für ... open{\nsub;\n{ command; }\n}; close- aber ich bin nicht sicher, ob das hier so ist ...
mikeserv

Hallo @mikeserv - Ich habe eine ähnliche Frage, die hier unter unix.stackexchange.com/questions/232509/… gestellt wird. Ihre Lösung funktioniert mit kleinen Dateien, aber ich habe eine große Datei und erhalte die Meldung "Speicherplatz überlaufen lassen". Fehlermeldung. Gibt es eine Chance, wie könnte ich das lösen? Vielen Dank
Narayan Akhade

@ NarayanAkhade - nein. jedenfalls nicht ohne überholung. es sei denn ... gibt es große Eingabeflächen, die nicht in {...}Blöcken enthalten sind? Wenn dies der Fall ist und Sie die erste Lösung verwenden, können Sie dies /{$/,/^}/Ham Anfang tun, anstatt nur H. Wenn Sie jedoch auch die zweite Lösung ausprobiert haben und dennoch denselben Fehler festgestellt haben, ist dies wahrscheinlich nicht hilfreich, da diese Lösung dies bereits tut. Und auch keinen Rabatt ed. Don bekam eine sehr gute Antwort hier und edangewandt werden kann temporäre Puffer zu verwenden , Dateien sehr einfach als auch, was mem Überschreitungen Puffer verhindern sollte.
Mikesserv

6

Hier ist eine Lösung mit ed:

ed -s filename <<< $'g/PATTERN/?{?,/}/p\nq\n'

das ist:

g/PATTERN/     # mark each line matching PATTERN  
?{?,/}/p       # for each marked line, print all lines from the previous { up to the next }  
q              # quit editor

Dies setzt voraus, dass PATTERNzwischen jedem Paar nur eine Zeile steht, { }andernfalls erhalten Sie für jede weitere Zeile PATTERNinnerhalb desselben Blocks eine doppelte Ausgabe .
Es funktioniert für mehrere, { }die eine einzelne Zeilenübereinstimmung enthalten, PATTERNz. B. für eine Testdatei mit PATTERNzwei verschiedenen Abschnitten:

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
}

Laufen

ed -s sample <<< $'g/PATTERN/?{?,/}/p\nq\n'

Ausgänge:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN again

another string here
}

Ich habe tatsächlich viel davon genommen! Vielen Dank!
Mikeserv

Ich weiß nicht einmal, dass dieser Befehl existiert. Danke
Rodrigo

4

Mit pcregrep:

pcregrep -M '(?s)\{[^}]*PATTERN.*?\}'

Oder mit GNU, grepsofern die Eingabe keine NUL-Bytes enthält:

grep -Poz '.*(?s)\{[^}]*PATTERN.*?\}'

0
$ awk 'BEGIN{RS="\n\n"; FS="[{}]"} {if ($2 ~ /string4/) {print $2}}' t1.txt
string4
string5
string6

wo:

  • string4 -> übereinstimmende Zeichenfolge
  • t1.txt -> enthält den in der Abfrage genannten Dateiinhalt

-2

sed -n '/ string / p' Dateiname

Wenn -n zu sed hinzugefügt wird, wird das Standardverhalten von sed unterdrückt. Diese Anweisung gibt Ihnen möglicherweise nicht genau das, was Sie möchten, sondern sollte nur die Zeichenfolge verschieben

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.