Extrahieren Sie einen Teil der Textdatei vom ersten Vorkommen einer Zeichenfolge bis zum ersten Vorkommen einer anderen

Extrahieren Sie einen Teil der Textdatei vom ersten Vorkommen einer Zeichenfolge bis zum ersten Vorkommen einer anderen

Wie kann ich einen Teil einer großen Textdatei extrahieren, beginnend beim ersten Vorkommen von FOO und endend beim ersten Vorkommen von BAR?

In meinem Fall versuche ich, einen Teil einer von mysqldump erstellten SQL-Datei zu extrahieren.

Antwort1

Anerkennung an@dgigUnd@Paulodie mir mit ihrem Feedback geholfen haben!Finale perlEinzeiler hier:

perl -lne 'if(/FOO/../BAR/){s/.*?(FOO)/$1/ if!$i++;s/BAR\K.*//&&print&&exit;print}' file

Erläuterung:

if(/FOO/../BAR/){        # perform the following actions on each line, starting
                         # with a line that contains FOO, and up to and including
                         # a line that contains BAR  
s/.*?(FOO)/$1/ if!$i++;  # only on the first line that contains FOO,
                         # delete all characters before FOO  
s/BAR\K.*//&&print&&exit;# if the line contains BAR, remove characters
                         # after BAR, print the line and stop processing  
print                    # simply print the line contents

Alte Antwort:

Anerkennung an@Paulofür eine einfache sedLösung. Es ist genauso einfach und leicht zu lesen awk:

awk '/FOO/,/BAR/' file

Es könnte jedoch zu einfach sein: Es gibt ganze Zeilen zurück und nicht genau „einen Textabschnitt, der beim ersten Vorkommen von FOO beginnt und beim ersten Vorkommen von BAR endet“. Ich glaube, das bedeutet, dass FOO das erste Wort und BAR das letzte sein sollte. Genau das zu tun, erfordert eine kompliziertere Antwort. Lassen Sie mich versuchen, dies in zu erreichen perl.

Einfacher Fall (gibt ganze Zeilen zurück):

perl -lne 'print if /FOO/../BAR/' file

Komplexer Fall (genau von FOO bis BAR):

perl -lne 'if(/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if!$i++;$_=~s/BAR\K.*//;print}' file

Mir gefällt diese gleichwertige Lösung, die dem Bereichsoperator eine Variable zuweist:

perl -lne 'if($a=/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if$a==1;$_=~s/BAR\K.*// if$a=~/E/;print}' file

Notiz:Es wird davon ausgegangen, dass nur ein Textabschnitt extrahiert werden muss, d. h. wir sollten nach dem ersten durch FOO und BAR abgegrenzten Absatz kein weiteres FOO vorfinden.

Ansonsten ist der einfache Fall schon nicht mehr so ​​einfach in awk:

awk '/FOO/,/BAR/ {print; if ($0~/BAR/) {exit} }' file

und in perl:

perl -lne '(print&&/BAR/&&exit) if /FOO/../BAR/' file

Und die komplexeren, ausgefeilteren Lösungen werden:

perl -lne 'if(/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if!$i++;$_=~s/BAR\K.*//&&print&&exit;print}' file

Und:

perl -lne 'if($a=/FOO/../BAR/){$_=~s/.*?(FOO)/$1/ if$a==1;$_=~s/BAR\K.*//&&print&&exit if$a=~/E/;print}' file

Dieses Beispiel zeigt, wie ein Einzeiler von außergewöhnlich klar und selbsterklärend zu einer scheinbar obskuren Folge zufälliger Zeichen werden kann, nur weil er das Problem ein wenig komplexer gemacht hat. Wo immer nötig, würde ich empfehlen, ein eigenständiges, wartbares und lesbares Skript zu schreiben, in dem zusätzliche Funktionen leicht hinzugefügt und Sonderfälle berücksichtigt werden können.

Antwort2

In diesem Fall war es nicht so schwierig, wie ich dachte. Mit sed, vom ersten Vorkommen von FOO bis zum ersten Vorkommen von BAR (ich habe es nicht versucht, aber wahrscheinlich wäre so etwas wie das zweite FOO bis zum zweiten BAR schwieriger.)

sed -nr '/FOO/ {
/FOO/ s/[^F]+FOO/FOO/p
:a
n
/BAR/ s/([^B]+BAR).*/\1/
p
/BAR/ q
ba
}' <<<'line1
> line2 FOO text1 FOO text2
> line3
> line4 BAR text3 BAR text4
> line5'

FOO text1 FOO text2
line3
line4 BAR

verwandte Informationen