パターンAにマッチし、次の行を含むパターンBにマッチした場合にのみそれを印刷する

パターンAにマッチし、次の行を含むパターンBにマッチした場合にのみそれを印刷する

私は、「search_string」という単語とその後の行、およびその前の「mod」に一致する行を含むすべての行を取得したいと考えています。
私は以下を試しました:

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

もっと良い方法はあるでしょうか?

ファイル:

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  

期待される出力:

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

答え1

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

説明:

  • を含む行はmodとして保存されますmd
  • を含む行は、以前に保存された、その行自体、および次の行search_stringを印刷するトリガーになります。md
  • if(md!="")これらは、1 つの( )の下に多数の -sがある場合に、md=""重複した行が生成されないようにするためのものです。modsearch_stringmodmod start3

注記:

  • と の両方を含む行でmodは、search_stringこのロジックが壊れます。

答え2

ファイルには「復帰」文字が含まれています。Unix では、これらを削除した方がよいでしょう。投稿した一連のコマンドが出力する内容 (復帰を削除したもの) を出力するには、次を試してください。

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

あるいはワンライナーとして:

$ 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  

(GNU) awk では複数文字のレコード区切り文字を使用できるため、レコード区切り文字を に設定しmod、 を含むレコードのみを印刷できますsearch_string。元のレコードを再構築するには、printf が必要です。

「予想される出力」として投稿した内容を印刷するには、次を試してください。

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

答え3

これを Python スクリプトで実行する場合:

# 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]))

関連情報