
別のファイルからの入力を使用して、ログファイルの特定の行を特定したいと思います。私はそれを行うためにこの小さなコマンドを使用しています:
while read line; do
grep "$line" service.log;
done < input_strings.txt > result.txt
input_strings.txt
約50,000の文字列(1行に1つ)があります。私は現在、これらの文字列のそれぞれについて巨大なservice.log
ファイル(約2,000,000行)を検索しています。
最初の文字列が10,000行に見つかり、input_strings.txt
この行が私のエントリに書き込まれるとします。その後、2番目の文字列が検索されますが、行1から始まります。service.log
result.txt
input_strings.txt
service.log
service.log
で最初の項目の最後の行を見つけることをどのように覚えていますかservice.log
?では、2番目の検索実行はどこで開始できますか?
答え1
一致を取得するためにループをまったく使用する必要はありません。単一のコマンドを使用する方がはるかに高速ですgrep
。
grep -Ff input_strings service.log > results.txt
つまり、質問に記載されている内容を文字通りに実行するには、変数を使用して最後の一致が見つかった行を追跡できます。
LINE_NUMBER=0
while read LINE; do
# Search for the next match starting at the line number of the previous match
MATCH="$(tail -n+${LINE_NUMBER} "service.log" | grep -n "${LINE}" | head -n1)";
# Extract the line number from the match result
LINE_NUMBER="${MATCH/:*/}";
# Extract the matching string from the match result
STRING="${x#*:}";
# Output the matching string
echo "${STRING}";
done < input_strings.txt > result.txt
答え2
最初のキーワードを検索し、一致した後に次のキーワードなどを検索し、一致を印刷したいようです。
一方keywords
:
foo
bar
そしてdata
:
bar 0
foo 1
bar 1
foo 2
awk
これを行う必要があるスクリプトは次のとおりです(GNU awkでテスト)。
$ awk 'BEGIN {i = j = 0} NR==FNR { k[i++] = $0; next}
$0 ~ k[j] {j++; print $0} j >= i {exit}' keywords data
foo 1
bar 1
i
0から始めて、j
最初のファイル(NR==FNR
現在のファイルのレコード/行番号を表示されている行の総数と比較)中にキーワードを配列として収集します。次にj
、:thキーワードを一致させ、j
一致すると印刷して増やします。すべてのキーワードを見つけて終了します。
のように、grep
ここのキーワードは実際に正規表現パターンですが、awk
ここでは明らかに正規表現です。固定文字列を検索するには代わりにindex($0, key)
を使用してください$0 ~ key
。
または、キーワードをロードせずに開始するには、次の手順を実行します。
$ awk -vkeyfile=keywords 'BEGIN {getline key < keyfile }
$0 ~ key {print $0; if (!getline key < keyfile) exit;}' data
foo 1
bar 1
これは簡単なはずです。