複数のファイルから文字列を検索し、そのファイル名のすべての項目を一覧表示する方法

複数のファイルから文字列を検索し、そのファイル名のすべての項目を一覧表示する方法

ディレクトリに多くのファイルがあり(Javaアプリケーションのログ - 1行に1つのレコード)、検索文字列を含むすべてのファイル名を一覧表示し、特定のファイルにその文字列が表示されるすべての項目を一覧表示したいと思います。

私はこれまでこれを使ってきました。ここではファイル名を取得し、以下では一致する行を取得しましたが、ファイル名の一致行がどのファイル名から来たのかわかりません。

#!/bin/bash
cd ${DIRECTORY}
clear
echo 'WARNINGS'
egrep -l "WARN" * | sort
echo ''
cat * | grep 'WARN'

すべてのファイル名(WARNを含む名前のみ)をリストし、一致するすべてのファイルの特定のファイルにWARN文字列を含むすべての行を表示する必要があります。

答え1

よく知られていないことは、grep複数のファイルを検索するときに(成功的に)検索したファイルの名前を印刷できることです。つまり、/dev/null検索するファイルのリストにそれを含めると、目的の結果が得られます。

$ grep "something" /path/to/file
something (and some other thing)

しかし:

$ grep "something" /dev/null /path/to/file
/path/to/file:something (and some other thing)

これにより、次のことができます。

$ find /path/to/start [-name "<filename pattern>"] \
                       -exec grep '<searchstr>' /dev/null {} \;

これにより、次の出力が提供されます。

/path/to/start/file1:<searchstr> foo
/path/to/start/file1:<searchstr> bar
/path/to/start/subdir/file2:foo <searchstr> bar
/path/to/start/subdir/file3:bar <searchstr> foo
...

@ilkkachuが正確に指摘したように、私が与えたコマンドは一度に1つのファイルをgrep。このプロセスを最適化する1つの方法は、次のように書くことです。

$ find /path/to/start [-name "<filename pattern>"] \
                       -exec grep '<searchstr>' /dev/null {} +

ここでfind複数のファイル名を一度にgrepに渡すと、grepがあまり頻繁に呼び出されないため、負荷が軽減されます。 1つのファイルしか検索でき/dev/nullないため、指定する必要があります。find

答え2

複数のファイルを に指定すると、grep出力の各行にファイル名が追加されます。さらに、これを行うと避けられます。猫のための古典的な役に立たない使用。これを使用する場合は、シェル変数名に大文字を使用しないでください。通常、グローバル環境変数名は大文字であるため、独自のシェル変数も大文字として使用すると、命名の競合とエラーが発生する可能性があります。最後に、廃止egrepされgrep -E(ここでは不要grep -E)、コンテンツを実行する前にそのディレクトリに移動する必要はありませんが、そうする場合は、作業を実行する前に正しく機能していることを確認する必要がありますcdcd必要なタスクを実行する拡張スクリプトのバージョンは次のとおりです。

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/*

これで、ターゲットディレクトリ名を引数として渡してスクリプトを実行できるようになりました。

your_script /path/to/target

たとえば、/home/terdon/foo私のシステムの指定されたディレクトリでそれを実行すると、次のようになります。

WARNINGS found in files in directory "/home/terdon/foo":
/home/terdon/foo/file2:WARNING from file2
/home/terdon/foo/file4:WARNING from file4
/home/terdon/foo/file4:WARNING2 from file4
/home/terdon/foo/file5:WARNING from file5

パスは表示せずにファイル名のみを表示するにはできるオプションcd(ただし、上記のように失敗した場合は終了する必要がありますcd):

#!/bin/sh

clear
if cd -- "$1"; then
  :
else
  echo "cd to '$1' failed!"
  exit 1
fi

printf 'WARNINGS found in files in directory "%s":\n' "$1"

grep 'WARN' *

または、出力からパスを削除することもできます。

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/* | sed 's|.*/||'

最後に、ターゲットディレクトリにファイルが1つしかない場合でもこれが機能することを確認するには、GNU grep(Linuxのデフォルト)を使用している場合は、-Hgrepに常にファイル名を含めるように指示するフラグを使用できます。

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep -H 'WARN' "$1"/* | sed 's|.*/||'

grepサポートされていない場合は、以下を使用して-Hください。バクニンのトリックこれには以下が含まれます/dev/null

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/* /dev/null | sed 's|.*/||'

答え3

より良い使用ackあなたの店にJava

これにより、ディレクトリや類似のディレクトリから検索するのを防ぎ、より高速で高速になります.git

grepこの状況よりも優れたオプションがあります。

頑張る(再帰的):

ack WARN
ack -l WARN

関連情報