web-dev-qa-db-ja.com

"find"を使って特定のファイル名を無視するにはどうすればいいですか?

私のお気に入りのBASHコマンドのひとつは、

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

指定されたSearchStringについて、現在のディレクトリ以下のすべてのファイルの内容を検索します。開発者として、これは時々便利になりました。

私の現在のプロジェクトと私のコードベースの構造のために、しかし、私は "。svn"を含むディレクトリの中または下にあるファイル、またはそれを含むファイルを検索しないことによってこのBASHコマンドをさらにもっともっとしたい".html"で終わる

見つけるためのMANページは私を混乱させます。私は-Pruneを使ってみましたが、奇妙な振る舞いをしました。 (開始するために).htmlページだけをスキップしようとして、私は試してみました。

find . -wholename './*.html' -Prune -exec grep 'SearchString' {} /dev/null \;

そして私が望んでいた行動を得られませんでした。私は-Pruneのポイントを見逃しているかもしれないと思います。あなたは私を助けてもらえますか?

ありがとう

130
Cody S

Findの否定(!)機能を使用して、特定の名前のファイルと一致させないことができます。

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

そのため、名前の末尾が.htmlであるか、パス内の任意の場所に.svnが含まれていると、一致しないため、execは実行されません。

181
Paul

私は長い間同じ問題を抱えていました、そして異なる状況に適用できるいくつかの解決策があります:

  • ack-grepは一種の "開発者のgrep"であり、はデフォルトではバージョン管理ディレクトリと一時ファイルをスキップします。 manページでは特定のファイルタイプのみを検索する方法と 自分で定義する方法 を説明しています。
  • grep自身の--exclude--exclude-dirオプションはファイルglobssingleディレクトリをスキップするためにとても簡単に使うことができます。ディレクトリ、残念ながら)。
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -Prune -o -print0 | xargs -0 grep ...は動作するはずですが、上記のオプションはおそらく長期的には面倒ではありません。
10
l0b0

次のfindコマンドは、名前.svnが含まれているディレクトリをPruneします。ディレクトリには降りませんが、整理されたパス名が出力されます(-name '*.svn'が原因です)。 。

grep -d skipでディレクトリ名を除外することができます。これはそのような入力「ディレクトリ名」を黙ってスキップします。

GNU grepでは、-Hの代わりに/dev/nullを使用できます。ちょっとした副次的な問題として、\+\;よりはるかに速い可能性があります。 100万行のファイルでは、\;を使用すると4m20s\+を使用すると1.2sしかかかりませんでした。

次の方法では、-execの代わりにxargsを使用し、どのファイルの名前にも改行\nがないと仮定します。ここで使用されているように、xargsはfindの\+とほとんど同じです。

xargsは、'\n'オプションを使用して入力区切り文字を-dに変更することによって、連続したスペースを含むファイル名を渡すことができます。

これは、名前.svnを含み、.htmlで終わらないファイルのみをgrepsするディレクトリを除外します。

find . \( -name '*.svn*' -Prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'
7
Peter.O