検索:プルーンは指定されたパスを無視しません


13

私は除外する必要が.git私からfind検索。それを達成するために、私は-path ./.git -pruneスイッチを使用しています:

$ find . -path ./.git -prune -o \( -type f -o -type l -o -type d \) | grep '.git'
./.git

ただし、これは.gitディレクトリの内容をスキップしますが、ディレクトリ自体をリストします。追加すると機能します-path ./.git -prune -o -print -a

find . -path ./.git -prune -o -print -a \( -type f -o -type l -o -type d \) | grep '.git'

なぜこれが必要なのですか。どちらのコマンドも同じ出力になるはずだと思いました。2番目の構文はかなり醜いです。


4
あなたは必要-printそうでない場合、暗黙的には、-print全体の条件に適用される
ステファンChazelas


回答:


3

manページfind

-prune True; if the file is a directory, do not  descend  into  it.  If
      -depth  is  given,  false;  no  effect.  Because -delete implies
      -depth, you cannot usefully use -prune and -delete together.

したがって、最初の例ではそうではないので、それ-path ./.git -pruneは真ではないので、デフォルトのアクション(-print)は呼び出されず、そのため、行が出力されます。


22

剪定されたディレクトリがfindコマンドによって出力される理由と、その他の複雑な機能の詳細についても混乱しまし-pruneたが、いくつかの例でそれを理解することができました。

以下の例を実行するには、次のディレクトリとファイルを作成します。

mkdir aa
mkdir bb
touch file1
touch aa/file1
touch bb/file3

この構造を作成するには:

$ tree

.
├── aa
   └── file1
├── bb
   └── file3
└── file1

次に、findを使用してという名前のディレクトリを探しますaa。ここで問題ありません。

$ find . -type d -name aa
./aa

aa以外のすべてのディレクトリを検索すると、現在のディレクトリ.andが取得され./bbます。これも意味があります。

$ find . -type d ! -name aa
.
./bb

これまでのところ良好ですが、を使用すると-prune、findはプルーニングしているディレクトリを返します。

$ find . -type d -name aa -prune
./aa

それはプルーニングされているディレクトリを返す理由はないで、説明-pruneで示したように、manページのセクションティモの答えが、中にEXPRESSIONSセクション:

式は以外のアクションが含まれていない場合は-prune、  -print式が真であるすべてのファイルに対して実行されます。

つまり、式はaaディレクトリ名と一致するため、式はtrueと評価され、find -printがコマンド全体の末尾に暗黙的にa を追加するため、出力されます。-printただし、意図的に-o -print最後にアクションを追加した場合、は追加されません。

find . -type d -name aa -prune -o -print
.
./file1
./bb
./bb/file3

ここで、findコマンドは暗黙を追加し-printないため、プルーニングするディレクトリ(aa)は出力されません。

最後に、ファイル名パターンがのfile*後にあるファイルを検索する句を追加する場合は、次のように2番目の句の最後に-oaを配置する必要があります-print

find . \( -type d -name aa -prune \) -o \( -type f -name 'file*' -print \)
./file1
./bb/file3

これが機能する理由は同じです-print。2番目の句にaを指定しない場合、-pruneアクション以外のアクションがないため、findは-printコマンドのTHE ENDに自動的に追加し、-prune句にプルーニングされたディレクトリ:

find . \( \( -type d -name aa -prune \) -o \( -type f -name 'file*' \) \) -print
./aa
./file1
./bb/file3

通常、-printコマンドは2番目の句に配置する必要があります。元のポスターのように中央に配置すると、プルーニングされているファイルがすぐに印刷され、2番目の句が必要なファイルを選択する機会がないため、正しく機能しません。

find . \( -type d -name aa -prune -o -print \) -o \( -type f -name 'file*' \)
.
./file1
./bb
./bb/file3

そのため、残念ながら、元のポスターは上記のコマンドを間違っ-printた場所に配置することで間違っていました。それは彼の特定のケースではうまくいったかもしれませんが、一般的なケースではうまくいきません。

どのように-prune機能するかを理解するのに苦労している何千人もの人々がいます。findmanページには、このコマンドについてネバーエンディング世界的な混乱を防ぐために更新する必要があります。


私のmanページ(Arch Linuxなどfind-4.6.0)は、「式全体に-pruneまたは-print以外のアクションが含まれていない場合、式全体が真であるすべてのファイルに対して-printが実行される」と述べています。しかし、あなたが説明するように動作します。
x-yuri 2017年

0

manページから、

ディレクトリツリー全体を無視するには、ツリー内のすべてのファイルをチェックするのではなく、-pruneを使用します。たとえば、ディレクトリ `src / emacs 'とその下のすべてのファイルとディレクトリをスキップし、見つかった他のファイルの名前を出力するには、次のようにします。

find . -path ./src/emacs -prune -o -print

だから、あなたが使うことができるかもしれません:

find . -path ./.git -prune -o -print

これは.gitディレクトリをリストしません。

特定のファイル名を指定するには、次のようにします。

find . -path ./.git -prune , -name filename

,カンマ演算子に注意してください。


-1

ここにすばやく簡単な方法があります:

find | fgrep -v /.git

findの複雑な構文を思い出せない...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.