私は、次のような多くのシーケンスを含む数千(約148,000行の長さ)のテキストファイルを持っています。
b 29.
b 52.
c 84.
c 83.
c 94.
c 93.
c 61.
b 38.
c 81.
c 92.
c 28.
c 37.
c 27.
...ファイルが大きすぎるため、次のようなパターンを検索できることを願っています(機能的ではない1行)。
grep "b\ 34.\nc53.\nb\ 54.\na\ 45.\nd\ 44.\nd\ 63.\nd\ 64.\n" ファイル名
awkが良い選択のようです。
これを行い、一致する行番号を印刷するにはどうすればよいですか?
答え1
これは複数行の文字列を取得するawkスクリプトです(一致項目は完全な行で構成する必要があります)。変数から検索するテキストを受け取りますneedle
。スクリプトは行ウィンドウw
(w
の行数はneedle
)を作成し、それと比較して機能しますneedle
。
awk -v needle='b 38.\nc 81.\nc 92.\n' '
BEGIN {
if (substr(needle, length(needle)) == "\n")
needle = substr(needle, 1, length(needle)-1);
w = split(needle, needles, "\n");
getline window
for (i = 2; i < w; i++) {getline; window = window "\n" $0}
}
{ window = window "\n" $0 }
window == needle {print NR - w + 1}
{ window = substr(window, index(window, "\n") + 1) }
' <data.txt
これは、データファイルのすべての行がパターンのすべての行と比較されるため、部分文字列を取得する最も効率的な方法ではありません。パターンでいくつかの事前計算を実行してより少ない数の比較を実行するより効率的なアルゴリズムがあります。ゴールドモリスプラット。
メモリに合ったファイルは一度に読み出してメモリから検索をします。探しているものがパターンマッチングだけであれば、これはPerlで簡単に実行できますが、Perlには効率的な線追跡のための基本的な要素がありません。以下は、複数行の文字列(そのまま渡す必要がある)を見つけるPythonスクリプトです。
import re, sys
needle = sys.argv[1]
haystack = sys.stdin.read()
pos = 0
line = 1
for m in re.finditer(needle, haystack):
line += haystack.count("\n", pos, m.start())
pos = m.start()
print line
使用法:python -c '…' $'b 38.\nc 81.\nc 92.\n' <data.txt
答え2
私は次のように書きます:
awk -v seven_lines="b 34.c 53.b 54.a 45.d 44.d 63.d 64." '
seven_lines == l6 l5 l4 l3 l2 l1 $0 {print "pattern found at line " (NR-6)}
{l6=l5; l5=l4; l4=l3; l3=l2; l2=l1; l1=$0}
'