多くのサブディレクトリ(例:abc/def/efg/(1..300)
)があるディレクトリ(例:abc/def/efg
)があります。これらのすべてのサブディレクトリには、共通のファイルがあります(例:file.txt
)。他のファイルを除いて、このfile.txt
でのみ文字列を検索したい。これどうやってするの?
grep -arin "pattern" *
を使用しましたが、サブディレクトリとファイルが多数ある場合は非常に遅くなります。
親ディレクトリでは、find
を使用してから、これらのファイルのみでgrep
を実行できます。
find . -type f -iname "file.txt" -exec grep -Hi "pattern" '{}' +
これにはfind
は必要ありません。 grep
は、これを単独で完全に処理できます。
grep "pattern" . -airn --include="file.txt"
man grep
から:
--exclude=GLOB
Skip files whose base name matches GLOB (using wildcard
matching). A file-name glob can use *, ?, and [...] as
wildcards, and \ to quote a wildcard or backslash character
literally.
--exclude-from=FILE
Skip files whose base name matches any of the file-name globs
read from FILE (using wildcard matching as described under
--exclude).
--exclude-dir=DIR
Exclude directories matching the pattern DIR from recursive
searches.
--include=GLOB
Search only files whose base name matches GLOB (using wildcard
matching as described under --exclude).
ファイル名を指定するために--include
フラグを指定してgrep
を実行する muruの答え で指定されている方法が、最良の選択であることがよくあります。ただし、これはfind
でも実行できます。
この回答のアプローチでは、find
を使用して、見つかった各ファイルに対してgrep
を個別に実行し、各ファイルへのパスを1回だけ出力します 、各ファイルで見つかった一致する行の上。 (一致するすべての行の前にパスを印刷する方法は、他の回答で説明されています。)
これらのファイルがあるディレクトリツリーの最上部にディレクトリを変更できます。次に実行します:
find . -name "file.txt" -type f -exec echo "##### {}:" \; -exec grep -i "pattern" {} \;
これは、.
という名前の各ファイルのパス(現在のディレクトリfile.txt
を基準とし、ファイル名自体を含む)を出力し、ファイル内の一致するすべての行が続きます。これは、{}
が見つかったファイルのプレースホルダーであるため機能します。各ファイルのパスは、#####
を前に付けることで内容とは別に設定され、そのファイルの一致する行の前に一度だけ出力されます。 (file.txt
と呼ばれる、一致するものを含まないファイルのパスは印刷されます。)この出力は、一致するすべての行の先頭にパスを印刷するメソッドから得られるものよりもすっきりしている場合があります。
このようにfind
を使用すると、everyファイル(grep -arin "pattern" *
)でgrep
を実行するよりもほとんど常に高速になります。これは、find
が正しい名前のファイルを検索して他のすべてのファイルをスキップするためです.
buntuはGNU find を使用します。これは {}
のように、より大きな文字列に表示される場合でも常に##### {}:
を展開します です。コマンドを必要とする場合 これをサポートしていない可能性のあるシステムでfind
を使用する場合 、または絶対に必要な場合にのみ-exec
アクションを使用する場合は、以下を使用できます。
find . -name "file.txt" -type f -printf '##### %p:\n' -exec grep -i "pattern" {} \;
出力を読みやすくするために、ANSIエスケープシーケンスを使用して色の付いたファイル名を取得できます。これにより、各ファイルのパス見出しは、その下に印刷される一致する行から目立ちやすくなります。
find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;
それは シェルを引き起こすエスケープコード を端末でグリーンを生成する実際のエスケープシーケンスに変え、通常の色のエスケープコードで同じことをする。これらのエスケープはfind
に渡され、ファイル名を出力するときにそれらが使用されます。 ($'
'
の引用は、find
の-printf
アクションがANSIエスケープコードを解釈するための\e
を認識しないため、ここで必要です。)
必要に応じて、代わりに-exec
を システムのprintf
コマンド (\e
をサポートします)と共に使用できます。同じことをする別の方法は次のとおりです。
find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;
質問の条件を文学的にとることができる場合、直接grepを使用できることを指摘するだけです。
grep 'pattern' abc/def/efg/*/file.txt
または
grep 'pattern' abc/def/efg/{1..300}/file.txt