特定のパスにあるファイルを除外して `grep`を実行する


12

./test/main.cpp検索からファイルを除外したい。

ここに私が見ているものがあります:

$ grep -r pattern --exclude=./test/main.cpp
./test/main.cpp:pattern
./lib/main.cpp:pattern
./src/main.cpp:pattern

パイプとフィルターの配置で複数のコマンドを使用することで、必要な出力を取得できることは知っていますが、grepネイティブに必要なものを理解するための引用/エスケープがありますか?


出力のフィルタリングに基づくソリューションは、関連する結果を除外する前にファイルを不必要に検索するため、うまくスケーリングしません。ディレクトリ全体を除外する場合(で--exclude-dir)、問題は拡大します。だからこそ、grepにネイティブに除外を実行させたいのです。
nobar

1
--exclude指定グロブないパス
ペルシア湾

回答:


6

grep 別のディレクトリに同じ名前のファイルが複数ある場合、特定のディレクトリのファイルに対してこれを行うことはできません。代わりにfindを使用します。

find . -type f \! -path './test/main.cpp' -exec grep pattern {} \+


なぜあなたはエスケープされている\!\+?バックスラッシュなしで正常に動作するようです。
nobar

@nobar一部の文字はシェルキーワードであるため、慣れています。エスケープされても何も起こらないので驚かないでしょう。
MichalH

grepできません、find代わりに使用してください」-完璧です。
nobar

4

GNUでは不可能だと思いますgrep。ただし、パイプは必要ありません。

find

find . ! -path ./test/main.cpp -type f -exec grep pattern {} +

zsh

grep pattern ./**/*~./test/main.cpp(.)

(.git、.svn ...を除外するだけでなく、隠しファイルも除外します)。


2

「失われた芸術」という本を書くことができましたxargsfind ... -exec … ';進水各ファイルに対してgrepを(しかし有する変異体-exec … +ません)。まあ、私たちは最近CPUサイクルを無駄にしています。ただし、パフォーマンスとメモリと電力が問題になる場合:xargsを使用します。

find . -type f \! -path 'EXCLUDE-FILE' -print0 | xargs -r0 grep 'PATTERN'

GNUのfind's -print0NUL出力を終了し、xargs' -0オプションはその形式を入力として受け入れます。これにより、ファイルの面白い文字が何であれ、パイプラインが混乱することがなくなります。この-rオプションfindは、何も見つからない場合でもエラーがないことを確認します。

次のようなことができるようになりました。

find . -type f -print0 | grep -z -v "FILENAME EXCLUDE PATTERN" | 
  xargs -r0 grep 'PATTERN'

GNU grep's -zはxargs 'と同じことをし-0ます。


3
いくつかの興味深いメモがありますが、パフォーマンスの問題について正しいかどうかはわかりません。私が理解してfind -exec (cmd) {} +いるように、それは同じようxargsfind -exec (cmd) {} \;動作し、同じように動作しxargs -n1ます。つまり、\;バージョンが使用されている場合にのみ、ステートメントは正しいです。
nobar

3
パイピングxargsは、使用するよりも効率的ではありません-exec … +(わずかですが)。ここの答えのどれも言及さえしません-exec … \;
ジル「SO-悪であるのをやめる」

1
まあ、s--t。私は自分とデートします。コメントと修正をありがとう。\ +はタイプミスだと思った。ああ、-exec ... +2005年1月に追加されました。ええ、私は時代遅れではありません... ... ...すべて。
オテウス

2

2008年にPOSIXに追加されたが、Solarisにはまだないfindサポートが-pathある場合:

find . ! -path ./test/main.cpp -type f -exec grep pattern /dev/null {} +

1
私はbecuase nobarは、他のディレクトリでmain.cppを望んでいることがうまくいくとは思わない
エリックRenouf

1
あなたのパターンは他のすべてのディレクトリからmain.cppも除外しませんか?それは望ましくないだろう
エリックルヌーフ

@EricRenouf:ああ、私の間違い、読み間違い。私の答えを更新しました。
クオンルム

@Gilles:なぜ-pathPOSIXではないのですか?
クオンルム

ああ、申し訳ありませんが、2008年に追加されました。Solarisにはまだありません。
ジル「SO-悪であるのをやめる」

1

記録のために、ここに私が好むアプローチがあります:

grep pattern $(find . -type f ! -path './test/main.cpp')

grepコマンドの先頭を保持することで、これはもう少し明確になったと思います-さらに、grep色の強調表示を無効にしません。ある意味でfindは、コマンド置換での使用は、grep機能の(制限された)ファイル検索サブセットを拡張/置換する方法にすぎません。


私にとって、find -exec構文は一種の不可解です。複雑な点の1つfind -execは、(場合によっては)さまざまな文字をエスケープする必要があることです(特に\;Bashで使用する場合)。おなじみのコンテキストに物事を入れるためだけに、次の2つのコマンドは基本的に同等です。

find . ! -path ./test/main.cpp -type f -exec grep pattern {} +
find . ! -path ./test/main.cpp -type f -print0 |xargs -0 grep pattern

サブディレクトリ除外する場合は、ワイルドカードを使用する必要がある場合があります。ここでスキーマを完全に理解していません- 秘儀について話してください:

grep pattern $(find . -type f ! -path './test/main.cpp' ! -path './lib/*' )

スクリプトで使用するためのfindベースのソリューションを一般化するためのもう1つの注意:grepコマンドラインには-H/ --with-filenameオプションを含める必要があります。それ以外の場合は、からの検索結果にファイル名が1つしか存在しないという状況下で、出力のフォーマットを変更しますfind。これはgrep、(の-rオプションを使用して)のネイティブファイル検索を使用する場合には必要ないように見えるため、注目に値します。

...さらに良いのは、/dev/null検索する最初のファイルとして含めることです。これにより、2つの問題が解決されます。

  • 検索するファイルが1つある場合、grep2つあると判断し、複数ファイル出力モードを使用します。
  • これにより、検索するファイルがない場合、grep1つのファイルがあると見なされ、stdinで待機することがなくなります。

最終的な答えは:

grep pattern /dev/null $(find . -type f ! -path './test/main.cpp')

findコマンド置換での出力を使用しないでください。スペースまたは他の特殊文字を含むファイル名がある場合、これは壊れます。を使用するとfind -exec、堅牢で使いやすいです。
ジル 'SO-悪であるのをやめる'

@Gilles:非常に良い点-また、出力はいくつかのプログラムのコマンドラインサイズの制限を超える可能性があります。買い手責任負担。
nobar

あー 「検索」構文は非常に困難です。「-o」は「or」演算子(Linuxでは「-or」)ですが、一般的な使用方法(「-prune」など)は論理的なorの概念に概念的にマップしません。それは論理的なORではなく、機能的なORです。
nobar

名前の一致に基づいてサブディレクトリを除外する別の方法:find -iname "*target*" -or -name 'exclude' -prune。まあ、それは一種の仕事です-剪定されたディレクトリはリストされますが、検索されません。あなたはそれがリストされたくない場合は、冗長なの並べ替えを追加することができます! -name 'exclude'
nobar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.