web-dev-qa-db-ja.com

ディレクトリの指定されたファイル名でのみパターン/テキストを再帰的に検索しますか?

多くのサブディレクトリ(例:abc/def/efg/(1..300))があるディレクトリ(例:abc/def/efg)があります。これらのすべてのサブディレクトリには、共通のファイルがあります(例:file.txt)。他のファイルを除いて、このfile.txtでのみ文字列を検索したい。これどうやってするの?

grep -arin "pattern" *を使用しましたが、サブディレクトリとファイルが多数ある場合は非常に遅くなります。

16

親ディレクトリでは、findを使用してから、これらのファイルのみでgrepを実行できます。

find . -type f -iname "file.txt" -exec grep -Hi "pattern" '{}' +
21
Zanna

これには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).
18
muru

ファイル名を指定するために--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" {} \;
8
sudodus

質問の条件を文学的にとることができる場合、直接grepを使用できることを指摘するだけです。

grep 'pattern' abc/def/efg/*/file.txt

または

grep 'pattern' abc/def/efg/{1..300}/file.txt
0
user216043