たとえば、パターンマッチングが次のような場合、隣接するマッチラインを探したいとします。
$ grep -n pattern file1 file2 file3
file1:10: ...
file2:100: ...
file2:1000: ...
file2:1001: ...
file3:1: ...
file3:123: ...
真ん中にある2つの一致を見つけたいです。
file2:1000: ...
file2:1001: ...
しかし、最初の2つと最後の2つではありません。
ベストアンサー1
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
正規表現と一致する場合は最後の行を含む変数を使用しますpat
。それ以外の場合は空の文字列が含まれます。
/pat/ && last {print last; print}
pat
この行が一致し、前の行も一致すると、両方の行last
が印刷されます。{last=""}
last
空の文字列に置き換える/pat/ {last=$0}
行が一致すると、その行に
pat
設定されます。last
これにより、次の行を処理するときに使用できます。
2つの連続ゲームを1つのグループとして扱う代替方法
次の拡張テストファイルを考えてみましょう。
$ cat file2
a
pat 1
pat 2
b
pat 3
c
pat 4
pat 5
pat 6
d
上記の解決策とは異なり、このコードは3つの連続した一致行を印刷するセットとして扱います。
$ 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
このコードは2つの変数を使用します。以前と同じです。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変数はファイル名を提供し、awkのFILENAME変数はFNR
ファイル内の行番号を提供します。
各ファイルの先頭からゼロに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