僅列印與模式相符的每行之前的第 N 行

僅列印與模式相符的每行之前的第 N 行

我試圖僅列印<N>搜尋模式之前的第 th 行。列印搜尋模式之前的grep -B<N>所有行。<N>我看到了 awk 代碼這裡只能列印<N>搜尋模式後的第 3 行。

awk 'c&&!--c;/pattern/{c=N}' file

如何修改它以僅列印<N>每行匹配之前的第 th 行pattern?例如,這是我的輸入文件

...
...
   0.50007496  0.42473932  0.01527831
   0.99997456  0.97033575  0.44364198
Direct configuration=     1
   0.16929051  0.16544726  0.16608723
   0.16984300  0.16855274  0.50171112
...
...
   0.50089841  0.42608090  0.01499159
   0.99982054  0.97154975  0.44403547
Direct configuration=     2
   0.16931296  0.16553376  0.16600890
   0.16999941  0.16847055  0.50170694  
...

我需要一個可以返回2nd line搜尋字串之前的命令Direct configuration。我正在嘗試運行這個SUSE Linux

答案1

需要使用行緩衝區。

試試這個:

awk -v N=4 -v pattern="example.*pattern" '{i=(1+(i%N));if (buffer[i]&& $0 ~ pattern) print buffer[i]; buffer[i]=$0;}' file

將值設定N為要列印的圖案之前的第 N 行。

pattern將值設定為要搜尋的正規表示式。

buffer是一個元素數組N。它用於儲存線路。每次找到該模式時,N都會列印該模式之前的第 3 行。

答案2

該程式碼不適用於前面的行。若要取得符合模式之前的行,您需要以某種方式儲存已處理的行。由於awk只有關聯數組,我想不出同樣簡單的方法來執行您想要的操作awk,因此這是一個 perl 解決方案:

perl -ne 'push @lines,$_; print $lines[0] if /PAT/; shift(@lines) if $.>LIM;' file 

變更PAT為您想要匹配的模式和LIM行數。例如,若要在每次出現 之前列印第 5 行foo,您可以執行:

perl -ne 'push @lines,$_; print $lines[0] if /foo/; shift(@lines) if $.>5;' file 

解釋

  • perl -ne:逐行讀取輸入檔並將給定的腳本套用到-e每一行。
  • push @lines,$_:將目前行( $_)加入到陣列中@lines
  • print $lines[0] if /PAT/:如果目前行與所需模式匹配,則列印數組中的第一個元素@lines( )。$lines[0]
  • shift(@lines) if $.>LIM;:$.是目前行號。如果大於限制,則從陣列中刪除第一個值@lines。結果是@lines總是有最後LIM幾行。

答案3

tac file | awk 'c&&!--c;/pattern/{c=N}' | tac

但是,當 N 行內有多個符合項目時,這與「轉送」用例具有相同的遺漏。

當輸入從正在運行的進程通過管道傳輸時,它不會很好地工作,但當輸入檔案完整且不增長時,這是最簡單的方法。

答案4

與 的替代方式sed

為了N=1:

sed '$!N; /.*\n.*pattern/P; D' FILE

為了N=2

sed '1N; $!N; /.*\n.*\n.*pattern/P; D' FILE

為了N=2情況下,第一行將讀取下一行N-1模式空間中的行然後開始一個N;P;D循環 - 讀取另一行,如果模式空間中的最後一行匹配,則列印模式空間中的第一行,然後刪除它,開始一個新的循環。

缺點是需要針對不同的值進行修改:

為了N=3:

sed '1{N;N}; $!N; /.*\n.*\n.*\n.*pattern/P; D' FILE

為了N=4:

sed '1{N;N;N}; $!N; /.*\n.*\n.*\n.*\n.*pattern/P; D' FILE

所以它很快就會變得很麻煩,儘管對於更大的值您可以準備一個腳本文件並將其傳遞給sed.

相關內容