2017-09-21 4 views
0

Ich habe Stunden wurde vorbei im Netz zu suchen, aber ich kann eine Lösung für ein Problem nicht finden, das nur so einfach aussieht ...sed Drucktext zwischen zwei Mustern und wählen n Vorkommen

ich habe eine Datei mit mehreren Mustererkennung

----PATERN1---- 
textaa1 
textbb1 
textcc1 
....... 
----PATERN2---- 
----PATERN1---- 
textaa2 
textbb2 
textcc2 
....... 
----PATERN2---- 
----PATERN1---- 
textaa2 
textbb2 
textcc2 
....... 
----PATERN2---- 
etc... 

Dies ist die Ausgabe i mit dem Befehl bekommen

sed -n '/PATERN1/,/PATERN2/p' file 

Aber die Frage ist, wie kann ich nur die n-te Vorkommen wählte? (1 - 2 bis 3 etc .. dass ich dann durch eine Variable ersetzen kann) Vielen Dank im Voraus

+1

post das gewünschte Ergebnis – RomanPerekhrest

+0

Ich gebe RomanPerekrest hier, sollten Sie die gewünschte Ausgabe in Ihre Frage erwähnen. Nicht einmal für deine Frage, sondern auch für die anderen Leser, die vielleicht auch in Zukunft Hilfe brauchen und von diesem Post bekommen könnten. – RavinderSingh13

Antwort

1

Dies könnte für Sie arbeiten (GNU sed):

sed -nr '/PATTERN1/H;//,/PATTERN2/G;/\n(\n[^\n]+){2}$/P' file 

den Halteraum verwendet als Gegen und drucke nur die Zeilen, die der erforderlichen Nummer entsprechen, dh oben ist die Nummer 2.

NB Nimmt an, dass PATTERN1 und PATTERN2 in der Datei übereinstimmen.

1

Es ist so einfach, aber Sie versuchen, das falsche Werkzeug zu verwenden. sed ist für s/old/new/, das ist alles und für alles andere, wie Sie tun, sollten Sie stattdessen awk verwenden.

$ awk -v n=2 ' 
    /PATERN1/ {f=1; rec=""} 
    f { 
     rec = rec $0 ORS 
     if (/PATERN2/) { 
      if (++c == n) { 
       printf "%s", rec 
      } 
      f=0 
     } 
    }' file 
----PATERN1---- 
textaa2 
textbb2 
textcc2 
....... 
----PATERN2---- 

Beachten Sie, dass die oben in jedem awk in jeder Schale in jedem UNIX-System arbeiten und mit den oben genannten Sie nicht für Ether PATERN mehrfach testen müssen, wenn Sie eine andere Datensatznummer wählen wollen drucken Sie einfach den Wert von n auf der Kommandozeile ändern, wenn Sie mehrere Datensätze durch ihre Zahlen seine triviale, offensichtlich zwicken drucken möchten:

$ awk -v n=2 -v m=7 ' 
    /PATERN1/ {f=1; rec=""} 
    f { 
     rec = rec $0 ORS 
     if (/PATERN2/) { 
      if ((++c == n) || (c == m)) { 
       printf "%s", rec 
      } 
      f=0 
     } 
    }' file 

wenn Sie nach einem bestimmten Text „foo“ testen wollen, innerhalb der Block statt (oder zusätzlich zu) Testen einer Zahl ist es auch trivial und offensichtlich:

$ awk ' 
    /PATERN1/ {f=1; rec=""} 
    f { 
     rec = rec $0 ORS 
     if (/PATERN2/) { 
      if (rec ~ /foo/) { 
       printf "%s", rec 
      } 
      f=0 
     } 
    }' file 

Wenn Sie bestimmte Zeilen in jedem Block drucken oder Zeilenumbrüche oder irgendetwas anderes entfernen möchten, ist es auch trivial und offensichtlich, weil das oben genannte das richtige Werkzeug für den Job verwendet.

+1

sehr klar, vielen Dank! – Phil95

0

Könnten Sie bitte versuchen, awk zu folgen, können Sie auch die Anzahl der Vorkommen angeben.

Hinzufügen einer nicht-Liner-Form der Lösung auch hier.

awk -v occur=2 -v regex1="PATERN1" -v regex2="PATERN2" ' 
(occur * 2)==count{ 
    print val; 
    val="" 
} 
$0 ~ regex1{ 
    count++ 
} 
$0 ~ regex2{ 
    count++ 
} 
{ 
    val=val?val ORS $0:$0 
} 
' Input_file 

Lösung 2.: Wenn Ihr input_file gebrochen ist und nicht über eine Folge von MUSTER1 mit PATTERN2 folgenden in jedem Block dann folgenden können Sie auch auf der gleichen helfen.

awk -v occur=2 -v regex1="PATERN1" -v regex2="PATERN2" ' 
$0 ~ regex1 && flag{ 
    val="" 
} 
(occur * 2)==count{ 
    print val 
    val="" 
    count="" 
} 
{ 
    val=val?val ORS $0:$0 
} 
$0 ~ regex1{ 
    count++ 
    flag=1 
} 
$0 ~ regex2 && count{ 
    count++ 
    flag="" 
} 
END{ 
    if((occur * 2)==count){ 
    print val 
} 
} 
' Input_file 

PS: Hier bin ich bedenkt, dass Vorkommen von Pattern1 zu Pattern2 bedeutet 1 Vorkommen.

PS für die 2. Lösung: Falls Sie wollen nichts, wenn Anzahl der Vorkommen drucken (für abgestimmte Strings/regex/Muster) NICHT dann count="" auch in $0 ~ regex1 && flag{ Block hinzufügen, indem Benutzer erwähnt gefunden hat.

Verwandte Themen