Muster A abgleichen und nur drucken, wenn Muster B übereinstimmt, einschließlich der folgenden Zeile

Muster A abgleichen und nur drucken, wenn Muster B übereinstimmt, einschließlich der folgenden Zeile

Ich möchte alle Zeilen abrufen, die das Wort „search_string“ enthalten, sowie die Zeile danach und die Zeile davor, die mit „mod“ übereinstimmt.
Ich habe Folgendes versucht:

grep -n 'mod\|search_string' ip | grep --before 1 search_string> inter  
grep -n --after 1 search_string ip >> inter  
sort -t':' -k1,1n -u inter -o op

Gibt es einen besseren Weg?

Datei:

mod start1  
some lines  
mod start2  
other lines  
mod start3  
 many other lines  
 search_string yada yada  
 hello  
 many other lines  
 search_string yada yada  
 bye  
mod start4  
 search_string baba baba  
 this too  
mod start5  

Erwartete Ausgabe :

mod start3  
 search_string yada yada   
 hello  
 search_string yada yada  
 bye  
mod start4  
 search_string baba baba  
 this too

Antwort1

awk '
   $0 ~ /mod/ { md=$0 }
   $0 ~ /search_string/ { if(md!="") { print md }; md="" ; print; getline; print }
   '

Erläuterung:

  • Eine Zeile mit modwird als gespeichert md.
  • Eine Zeile mit search_stringlöst das Drucken des zuvor gespeicherten aus md, der Zeile selbst und der nächsten Zeile.
  • if(md!="")und md=""sollen sicherstellen, dass Sie keine doppelten Zeilen erhalten , wenn sich viele -s unter einem einzigen modbefinden ( in Ihrem Beispiel).search_stringmodmod start3

Notiz:

  • Eine Zeile, die sowohl modals auch enthält search_string, unterbricht diese Logik.

Antwort2

Ihre Datei enthält "Wagenrücklauf"-Zeichen. Unter Unix ist es besser, diese zu entfernen. Um die von Ihnen gepostete Befehlsfolge auszudrucken (ohne Wagenrückläufe), versuchen Sie Folgendes:

awk '{gsub(/\r/,"")}
     /mod/          { a = $0 }
     /search_string/{ if(a!=""){print(a);a=""}
                      print;getline;print
                    }
    ' infile

Oder als Einzeiler:

$ awk '{gsub(/\r/,"")}/mod/{a=$0}/search_string/{if(a!=""){print(a);a=""}print;getline;print}' infile

mod start3  
 search_string yada yada  
 hello  
 search_string yada yada  
 bye  
mod start4  
 search_string baba baba  
 this too  

Da es in (GNU) awk möglich ist, einen mehrstelligen Datensatztrenner zu verwenden, können wir den Datensatztrenner auf setzen modund nur Datensätze drucken, die enthalten search_string. printf ist erforderlich, um den ursprünglichen Datensatz wiederherzustellen.

Um das auszudrucken, was Sie als „Erwartete Ausgabe“ gepostet haben, versuchen Sie Folgendes:

awk '/search_string/{printf("mod%s", $0)}' RS=mod infile

Antwort3

Wenn Sie dies in einem Python-Skript möchten:

# Read file into memory.
with open('myfile.txt') as f:
    lines = [line.rstrip() for line in f]

# Loops through lines backwards, looking for string and optionally mod.
output_lines = list()
find_mod = False
for i, line in enumerate(lines[::-1]):
    if 'search_string' in line:
        output_lines.append(lines[::-1][i-1])
        output_lines.append(lines[::-1][i])
        find_mod = True
    elif find_mod and 'mod' in line:
        output_lines.append(lines[::-1][i])
        find_mod=False

print("\n".join(output_lines[::-1]))

verwandte Informationen