web-dev-qa-db-ja.com

複数のファイルで最後に出現する文字列を見つける

文字列の最後の出現を見つけるには、複数のログファイル(過去24時間に生成されたすべてのファイル、すべて同じディレクトリに保存されている)を検索する必要があります。これは私が書いたコマンドです:

find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1

しかし、これは1つのファイルの最後の行のみを返します。これを調整してすべての行を取得する方法に関する提案はありますか?

9
Lokesh

GNUファシリティ:

find . -mtime -1 -exec bash -c \
'for f; do tac "$f" | grep -m1 fileprefix; done' _ {} +
4
iruvar

すべてが単一のディレクトリにある場合は、次のようにすることができます。

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

ファイル名も印刷する必要がある場合は、各grep呼び出しに-Hを追加します。または、grepがサポートしていない場合は、/dev/nullも検索するように伝えます。出力は変更されませんが、grepには複数のファイルが指定されているため、ヒットごとに常にファイル名が出力されます。

for file in *fileprefix*; do
    grep 'search string' "$file" /dev/null | tail -1
done
8
terdon
find . ! -name . -Prune -mtime 1 -name 'fileprefix*' \
     -exec sed -se'/searchstring/h;$!d;x' {} +

... GNU sed-separate filesオプションとPOSIX findをサポートしている場合に機能します。

ただし、! -type dまたは-type f修飾子を追加する必要があります。ディレクトリを読み取ろうとしてもあまり役に立ちません。通常のファイルに範囲をさらに狭めると、パイプまたはシリアルデバイスでの読み取りのハングを回避できます。ファイル。

ロジックは非常にシンプルです。sedは、hに一致する入力行のコピーでsearchstringoldスペースを上書きし、次にすべての入力行を出力からdeletesします。各入力ファイルの最後。最後の行に到達すると、e xはそのホールドスペースとパターンスペースを変更します。そのため、ファイルの読み取り中にsearchstringが見つかった場合、最後に発生したものが自動出力されて出力されます。空白行を書き込みます。 (望ましくない場合は、sedスクリプトの末尾に/./!dを追加します)

これは、いくつかの65k入力ファイルごとにsedを1回呼び出すか、またはARG_MAXの制限が何であっても実行します。これは非常にパフォーマンスの高いソリューションであり、非常に簡単に実装できます。

ファイル名も必要な場合は、最近のGNU sedを指定すると、Fコマンドを使用して別の行に書き出すことができます。 -printの後に+プライマリを追加することにより、バッチごとに別のリストでfindによって印刷されます。

4
mikeserv

どうですか:

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 
1
Dmitry Aleks
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オプションを使用して、常にすべての一致のファイル名と行番号の両方を出力し、次にファイル名とlinenumber、それをawkにパイプし、各ファイル名の最後の一致を配列に格納し、最終的に出力します。

かなり力ずくの方法ですが、機能します。

1
cas