文字列の最後の出現を見つけるには、複数のログファイル(過去24時間に生成されたすべてのファイル、すべて同じディレクトリに保存されている)を検索する必要があります。これは私が書いたコマンドです:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
しかし、これは1つのファイルの最後の行のみを返します。これを調整してすべての行を取得する方法に関する提案はありますか?
文字列の最後の出現を見つけるには、複数のログファイル(過去24時間に生成されたすべてのファイル、すべて同じディレクトリに保存されている)を検索する必要があります。これは私が書いたコマンドです:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
しかし、これは1つのファイルの最後の行のみを返します。これを調整してすべての行を取得する方法に関する提案はありますか?
回答:
GNUファシリティを想定:
find . -mtime -1 -exec bash -c \
'for f; do tac "$f" | grep -m1 fileprefix; done' _ {} +
find
使用してファイルに対してコマンドを実行できます-exec
。を使用してbash -c
、bash
によって検出されたファイルをループしてfind
実行するシェルを生成tac .. | grep -m1 fileprefix
します
-d" "
カットで使用します。単一引用符ではなく二重引用符
find
コマンドは、ファイルのプレフィックスをフィルタリングできます。これはgrep
必要ありません。検索文字列がこの回答に含まれていないことも驚くべきことです。
すべてが単一のディレクトリにある場合は、次のようにすることができます。
for file in *fileprefix*; do
grep 'search string' "$file" | tail -1
done
これらが大きなファイルである場合は、を使用tac
してファイルを逆順で印刷し(最後の行を最初に)、次にgrep -m1
最初の出現と一致させることで、速度を上げる価値があるかもしれません。これにより、ファイル全体を読み取る必要がなくなります。
for file in *fileprefix*; do
tac file | grep -m1 'search string'
done
どちらも、に一致するディレクトリがないことを前提としていますfileprefix
。存在する場合は、無視できるエラーが表示されます。問題がある場合は、ファイルのみを確認します。
for file in *fileprefix*; do
[ -f "$file" ] && tac file | grep -m1 'search string'
done
ファイル名も印刷する必要がある場合は、-H
各grep
呼び出しに追加してください。または、grep
サポートしていない場合は、も検索するように伝えます/dev/null
。出力は変更されませんが、grep
複数のファイルが指定されているため、ヒットごとに常にファイル名が出力されます。
for file in *fileprefix*; do
grep 'search string' "$file" /dev/null | tail -1
done
tac
。最初の一致が見つかるとすぐに終了します。832Mのテキストファイルと最後の行にあるパターンでテストしました。grep -m 1 pattern file
ツール〜7秒とtac file | grep -m1 pattern
かかりました0.009
。
find . ! -name . -prune -mtime 1 -name 'fileprefix*' \
-exec sed -se'/searchstring/h;$!d;x' {} +
... ファイルsed
の-s
分離オプションとPOSIX をサポートするGNU を使用している場合に機能しますfind
。
ただし、! -type d
orまたは-type f
修飾子を追加する必要があります。ディレクトリを読み取ろうとしてもあまり役に立ちません。通常のファイルに範囲をさらに狭めると、パイプまたはシリアルデバイスファイルでの読み取りのハングを回避できます。
ロジックは非常に簡単です- sed
その上書きh
一致する入力行のコピーと古い領域をsearchstring
、その後、d
出力から全ての入力ラインが、各入力ファイルの最後のをeletes。最後の行に到達x
すると、保持スペースとパターンスペースが変更されます。そのためsearchstring
、ファイルの読み取り中に見つかった場合は、最後に発生したものが自動出力されて出力され、それ以外の場合は空白行が書き込まれます。(それが望ましくない場合/./!d
は、sed
スクリプトの末尾に追加してください)。
これによりsed
、65kの入力ファイルごとに1 回の呼び出しが行われますARG_MAX
。これは非常に高性能なソリューションであり、非常に簡単に実装できます。
ファイル名も必要な場合は、最近のGNU sed
を指定して、F
コマンドを使用してそれらを別々の行に書き出すか、または後にプライマリをfind
追加することにより、バッチごとに個別のリストで出力することができます。-print
+
どうですか:
find . -mtime -1 -name "fileprefix*" -exec sh -c \
'echo "$(grep 'search string' $1 | tail -n 1),$1"' _ {} \;
上記は、各ファイルで最後に検索文字列が出現し、その後にコンマの後にそれぞれのファイル名が続く、素晴らしい出力を提供します(エコーの下の "、$ 1"部分を変更して、フォーマットを変更するか、不要であれば削除します)。「file」という名前の接頭辞が付いたファイルで「10」の検索文字列を検索するサンプル出力は次のとおりです。
[dmitry@localhost sourceDir]$ find . -mtime -1 -name "file*" -exec sh -c 'echo "$(grep '10' $1 | tail -n 1),$1"' _ {} \;
Another data 02 10,./file02.log
Some data 01 10,./file01.log
Yet another data 03 10,./file03.log
find . -mtime 1 -name 'fileprefix*' -exec grep -Hn 'search string' {} + |
sort -t: -k1,2 -n |
awk -F: '{key=$1 ; $1="" ; $2="" ; gsub(/^ /,"",$0); a[key]=$0}
END {for (key in a) { print key ":" a[key] }}'
これは、GNU使用grep
の-H
と-n
、常にファイル名とすべてのマッチの行番号の両方を印刷するオプションが、それはファイル名と行番号でソートし、パイプをAWKに、アレイ内の各ファイル名の最後の試合を格納すると、最終的に印刷しますそれ。
かなり力ずくの方法ですが、機能します。