it-swarm.com.de

Zeilen zwischen zwei Markierungsmustern auswählen, die bei awk/sed mehrfach vorkommen können

Mit awk oder sed wie kann ich Linien auswählen, die zwischen zwei verschiedenen Markierungsmustern liegen? Es kann mehrere Abschnitte geben, die mit diesen Mustern gekennzeichnet sind.

Zum Beispiel: Angenommen, die Datei enthält: 

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

Und das Startmuster ist abc und das Endmuster ist mnoSo. 

def1
ghi1
jkl1
def2
ghi2
jkl2

Ich verwende sed, um das Muster einmal anzupassen: 

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

Gibt es eine Möglichkeit in sed oder awk, bis zum Ende der Datei wiederholt zu arbeiten? 

103
dvai

Verwenden Sie awk mit einem Flag, um den Druck bei Bedarf auszulösen:

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

Wie funktioniert das?

  • /abc/ stimmt mit Zeilen überein, die diesen Text enthalten, ebenso wie /mno/
  • /abc/{flag=1;next} legt die flag fest, wenn der Text abc gefunden wird. Dann wird die Zeile übersprungen. 
  • /mno/{flag=0} setzt die flag zurück, wenn der Text mno gefunden wird.
  • Die letzte flag ist ein Muster mit der Standardaktion, nämlich print $0: Wenn flag gleich 1 ist, wird die Zeile gedruckt.

Eine ausführlichere Beschreibung und Beispiele sowie Fälle, in denen die Muster angezeigt werden oder nicht, finden Sie unter Auswahl von Linien zwischen zwei Mustern. .

161
fedorqui

sed verwenden:

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

Die Option -n bedeutet, dass standardmäßig nicht gedruckt wird.

Das Muster sucht nach Zeilen, die nur abc bis mno enthalten, und führt dann die Aktionen im { ... } aus. Die erste Aktion löscht die abc-Zeile. die zweite die Variable mno; und p gibt die verbleibenden Zeilen aus. Sie können die Regexen nach Bedarf entspannen. Zeilen außerhalb des Bereichs abc..mno werden einfach nicht gedruckt.

38

Das könnte für Sie funktionieren (GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

Löschen Sie alle Zeilen mit Ausnahme der Zeilen zwischen abc und mno.

17
potong
sed '/^abc$/,/^mno$/!d;//d' file

golfen zwei Charaktere besser als ppotong's{//!b};d

Die leeren Schrägstriche // bedeuten: "den zuletzt verwendeten regulären Ausdruck wiederverwenden". und der Befehl funktioniert wie das verständlichere:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

Dieses scheint POSIX zu sein :

Wenn ein RE leer ist (dh es wird kein Muster angegeben), verhält sich sed so, als ob das letzte im letzten Befehl verwendete RE (entweder als Adresse oder als Teil eines Ersatzbefehls) angegeben wurde.

Von den Links der vorherigen Antwort war dies einer, der ksh unter Solaris ausführte:

sed '1,/firstmatch/d;/secondmatch/,$d'
4
FanDeLaU

Don_crisstis Antwort von Zeige nur Text zwischen 2 übereinstimmenden Mustern ?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

das ist viel effizienter als die Anwendung von AWK, siehe hier .

so etwas funktioniert für mich:

file.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

mit: awk -f file.awk data...

edit: O_o fedorqui Lösung ist viel besser/schöner als meine.

1
pataluc
Perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
1
Vijay

Ich habe versucht, awk zu verwenden, um Zeilen zwischen zwei Mustern zu drucken, während pattern2 auch pattern1 entspricht. Und die Linie pattern1 sollte auch gedruckt werden. 

z. B. Quelle 

package AAA
aaa
bbb
ccc
package BBB
ddd
eee
package CCC
fff
ggg
hhh
iii
package DDD
jjj

sollte eine Ausgabe von haben

package BBB
ddd
eee

Wo Muster1 package BBB ist, ist Muster2 package \w*. Beachten Sie, dass CCC kein bekannter Wert ist und daher nicht wörtlich abgeglichen werden kann.

In diesem Fall funktionieren weder awk '/abc/{a=1}/mno/{print;a=0}a' file von @scai noch awk '/abc/{a=1} a; /mno/{a=0}' file von @fedorqui für mich.

Zum Schluss gelang es mir, es durch awk '/package BBB/{flag=1;print;next}/package \w*/{flag=0}flag' file zu lösen, haha

Etwas mehr Aufwand führt zu awk '/package BBB/{flag=1;print;next}flag;/package \w*/{flag=0}' file, um auch die pattern2-Zeile zu drucken, dh

package BBB
ddd
eee
package CCC
0
Weekend