2012-03-05 23:28:16 +0000 2012-03-05 23:28:16 +0000
148
148

find "を使って特定のファイル名を無視するには?

私のお気に入りのBASHコマンドの一つに

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

指定したSearchStringでカレントディレクトリ以下のファイルの内容を全て検索することです。開発者としては、これが便利なことがあります。

しかし、私の現在のプロジェクトとコードベースの構造上、「.svn」を含むディレクトリ以下のファイルや「.html」で終わるファイルを検索しないようにすることで、このBASHコマンドをもっと高度なものにしたいと思っています

findのMANページはちょっと混乱しました。私は-pruneを使ってみましたが、奇妙な動作をしました。.htmlページだけをスキップしようとして(開始するために)

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

を試してみましたが、期待していたような動作は得られませんでした。私は -prune のポイントを見落としているかもしれません。助けてもらえますか?

ありがとう

回答 (3)

209
209
209
2012-03-06 00:40:37 +0000

find の否定 (!) 機能を使って、特定の名前のファイルにマッチしないようにすることができます:

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

つまり、名前の末尾が .html で終わっていたり、パスのどこかに .svn が含まれていたりすると、マッチしないので exec は実行されません。

12
12
12
2012-03-06 13:54:15 +0000

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

  • 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 ... は動作するはずですが、長い目で見ると上記のオプションの方が手間が少ないかもしれません。
9
9
9
2012-03-06 03:29:21 +0000

以下の find コマンドは、ディレクトリ名に _.svn が含まれるディレクトリを prune していますが、ディレクトリ内には降りませんが、prune されたパス名が表示されます・・・(-name '*.svn' が原因です!) …

でディレクトリ名をフィルタリングできます。grep -d skip これは、このような入力された “ディレクトリ名 "を黙ってスキップします。

GNU grepでは、-Hの代わりに/dev/nullを使うことができます。ちょっとした副次的な問題として、の方が`\;`よりもはるかに速いことがあります。例えば、100万個の1行ファイルを処理する場合、`\;`を使った場合は_4m20s_かかりましたが、を使った場合は1.2sしかかかりません。

以下の方法では、xargsの代わりに-execを使用し、ファイル\nの改行がないと仮定しています。ここで使用する場合、xargsはfindの``とほとんど同じです。

xargs は、'\n' オプションで入力デリミタを -d に変更することで、連続したスペースを含むファイル名を渡すことができます。

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

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