Text-Processing

在相鄰行上查找匹配項

  • April 26, 2016

我想找到相鄰的匹配行,例如,如果模式匹配是

$ grep -n pattern file1 file2 file3
file1:10: ...
file2:100: ...
file2:1000: ...
file2:1001: ...
file3:1: ...
file3:123: ...

我想找到中間的兩個匹配項:

file2:1000: ...
file2:1001: ...

但不是前兩個和後兩個。

我將使用與 thrig 相同的測試文件:

$ cat file
a
pat 1
pat 2
b
pat 3

這是一個 awk 解決方案:

$ awk '/pat/ && last {print last; print} {last=""} /pat/{last=$0}' file
pat 1
pat 2

這個怎麼運作

awk隱式循環文件中的每一行。該程序使用一個變數 ,last如果它與 regex 匹配,則該變數包含最後一行pat。否則,它包含空字元串。

  • /pat/ && last {print last; print}

如果pat匹配此行和上一行,last, 也是匹配,則列印這兩行。

  • {last=""}

替換last為空字元串

  • /pat/ {last=$0}

如果此行匹配pat,則設置last為此行。這樣,當我們處理下一行時,它將可用。

將> 2個連續匹配視為一組的替代方法

讓我們考慮這個擴展的測試文件:

$ cat file2
a
pat 1
pat 2
b
pat 3
c
pat 4
pat 5
pat 6
d

與上面的解決方案不同,此程式碼將三個連續的匹配行視為一組要列印:

$ awk '/pat/{f++; if (f==2) print last; if (f>=2) print; last=$0; next} {f=0}' file2
pat 1
pat 2
pat 4
pat 5
pat 6

此程式碼使用兩個變數。和以前一樣,last是上一行。此外,f計算連續匹配的次數。f因此,我們在2 或更大時列印匹配行。

添加類似 grep 的功能

為了模擬grep問題中顯示的輸出,此版本在每個匹配行之前列印文件名和行號:

$ awk 'FNR==1{f=0} /pat/{f++; if (f==2) printf "%s:%s:%s\n",FILENAME,FNR-1,last; if (f>=2) printf "%s:%s:%s\n",FILENAME,FNR,$0; last=$0; next} {f=0}' file file2
file:2:pat 1
file:3:pat 2
file2:2:pat 1
file2:3:pat 2
file2:7:pat 4
file2:8:pat 5
file2:9:pat 6

awk 的 FILENAME 變數提供文件名,awkFNR提供文件中的行號。

在每個文件的開頭FNR==1,我們重置f為零。這可以防止一個文件的最後一行被認為與下一個文件的第一行是連續的。

對於那些喜歡他們的程式碼分佈在多行的人來說,上面看起來像:

awk '
   FNR==1{f=0}
   /pat/ {f++
       if (f==2) printf "%s:%s:%s\n",FILENAME,FNR-1,last
       if (f>=2) printf "%s:%s:%s\n",FILENAME,FNR,$0
       last=$0
       next
   }

   {f=0}
   ' file file2

引用自:https://unix.stackexchange.com/questions/278404