shで「検索」の「-prune」オプションを使用する方法


219

の例がよくわかりませんman find。例や説明を教えてもらえますか?正規表現を組み合わせることができますか?


より詳細な質問は次のとおりです:

changeallようなインターフェイスを持つシェルスクリプトを記述しますchangeall [-r|-R] "string1" "string2"。これは、サフィックスを持つすべてのファイルを検索します.h.C.cc、または.cppとのすべての出現に変更string1するとstring2-r現在のディレクトリのみにとどまるか、サブディレクトリを含むかのオプションです。

注意:

  1. 非再帰的な場合lsは許可されていません。使用できるのはfindおよびのみsedです。
  2. 試しましたfind -depthがサポートされていませんでした。だから私は-prune助けることができるのかと思っていましたが、の例が理解できませんでしたman find

EDIT2:私は割り当てを行っていましたが、自分で仕上げたいので、詳細については質問しませんでした。私はすでにそれを実行して提出したので、ここで質問全体を述べることができます。また、を使わずに何とか課題を終えることができましたが、-pruneとにかく学びたいと思います。

回答:


438

私が混乱させたの-pruneは、それ-printがテスト(など-name)ではなく、アクション(など)であることです。「やること」リストを変更しますが、常にtrueを返します

使用するための一般的なパターン-pruneは次のとおりです。

find [path] [conditions to prune] -prune -o \
            [your usual conditions] [actions to perform]

テストの最初の部分(まで)は、実際に必要なもの(つまり、プルーニングしたくないもの)に対してfalseを返すため、ほとんど常に-o(論理OR)の直後が必要です。-prune-prune

次に例を示します。

find . -name .snapshot -prune -o -name '*.foo' -print

これにより、「。snapshot」ディレクトリの下にない「* .foo」ファイルが見つかります。この例では、-name .snapshot構成する[conditions to prune]、と-name '*.foo' -printある[your usual conditions][actions to perform]

重要な注意事項

  1. やりたいことがすべて結果を印刷する場合は、-printアクションを省略することに慣れている可能性があります。通常、を使用する場合は、そのようなことはしたくないでしょう-prune

    最後に(皮肉なことに)アクション以外のアクションがない場合、findのデフォルトの動作は、アクション全体で全体を「および」にします。つまり、これを書くということです:-print-prune

    find . -name .snapshot -prune -o -name '*.foo'              # DON'T DO THIS

    これを書くのと同じです:

    find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS

    つまり、プルーニングしているディレクトリの名前も出力されます。これは通常、希望するものではありません。代わりに、それが必要な-print場合は、アクションを明示的に指定することをお勧めします。

    find . -name .snapshot -prune -o -name '*.foo' -print       # DO THIS
  2. 「通常の状態」がプルーニング状態にも一致するファイルと一致する場合、それらのファイルは出力に含まれません。これを修正する方法は、-type d述語をプルーン条件に追加することです。

    たとえば、で始まるディレクトリ.gitを削除したいとします(これは確かに多少の不自然です-通常は正確に 名前を付けたものを削除するだけで済みます.git)が、それ以外はのようなファイルを含むすべてのファイルを表示したいとします.gitignore。あなたはこれを試すかもしれません:

    find . -name '.git*' -prune -o -type f -print               # DON'T DO THIS

    これは出力に含まれません.gitignore。これが修正バージョンです:

    find . -name '.git*' -type d -prune -o -type f -print       # DO THIS

追加のヒント:のGNUバージョンを使用している場合find、のtexinfoページにfindは、そのマンページよりも詳細な説明があります(ほとんどのGNUユーティリティに当てはまります)。


6
テキストでは100%明確ではありませんが( '* .foo'のみを印刷するため、競合はありません)、-prune部分は「.snapshot」という名前の何も(ディレクトリだけでなく)印刷しません。つまり、-pruneディレクトリでのみ機能するわけではありません(ただし、ディレクトリの場合、その条件に一致するディレクトリ(つまり、ここではに一致するディレクトリ)に入るのを防ぎます-name .snapshot)。
Olivier Dulac 2013年

12
+1は、きちんと行われた説明(そして特に重要な注意)を示します。これは、find開発者に提出する必要があります(manページでは、通常の人間の「プルーン」については説明されていないため、^ ^理解するのに何度も試行錯誤しましたが、警告されている副作用はわかりませんでした)。
Olivier Dulac 2013年

2
@OlivierDulacこれは、保持したいファイルを潜在的に除去することに関して非常に良い点です。これを明確にするために、回答を更新しました。-pruneちなみに、これを引き起こすのは実際にはそれ自体ではありません。問題は、or演算子が「ショートサーキット」であり、orがandよりも優先順位が低いことです。最終結果はと呼ばれるファイルがあればということで.snapshot遭遇したことが最初にマッチします-name-pruneその後、何もしません(ただし、trueを返す)、およびその左引数がtrueだったので、その後、またはtrueを返します。アクション(例:)-printは2番目の引数の一部であるため、実行する機会はありません。
ローレンスゴンサルベス2013年

3
最後に+1が必要な理由をようやく見つけたので-print、これに加え\! -path <pattern>て追加を停止できます-prune
Miserable Variable

6
"-o"は "-or"の省略形であり、(POSIX準拠ではありませんが)より明確に読み取れることに注意してください。
ヨーヨー2014

27

通常、Linuxで物事を行うネイティブな方法と、左から右へと考える方法です。
したがって、最初に探しているものを書きます。

find / -name "*.php"

次に、おそらくEnterキーを押して、ディレクトリから取得したくないファイルが多すぎることに気付きます。マウントされたドライブを検索しないように/ mediaを除外しましょう。
次のコマンドを前のコマンドに追加するだけです。

-print -o -path '/media' -prune

したがって、最後のコマンドは次のとおりです。

find / -name "*.php" -print -o -path '/media' -prune

............... | <---含める---> | .................... | <- --------除外---------> |

この構造ははるかに簡単で、正しいアプローチと相関していると思います


3
これが効率的であるとは思っていませんでした。プルーンの前に左の句を最初に評価すると思っていましたが、驚いたことに、簡単なテストでfindは、-prune句を最初に処理するのに十分賢いようです。うーん、面白い。
artfulrobot 14

私は、GNU findを使用してから10年近く経ったとは考えていませんでした。有難うございます!これからの考え方は間違いなく変わるでしょう-prune
フェリペアルバレス2016

3
@artfulrobotそれは本当に最初にそれを処理していますか?それが入っていると思っていて/media、呼び出されていないことに気づいてから、*.phpそれが現在中にあるかどうかを確認し、それが含まれていることを確認し/mediaて、サブツリー全体をスキップします。それはまだ左から右にあり、両方のチェックが重ならない限り違いはありません。
phk 2016年

26

-pruneが下降に防ぐことはできませんので注意してください任意のいくつかが言ってきたようにディレクトリ。適用先のテストに一致するディレクトリへの下降を防ぎます。おそらく、いくつかの例が役立ちます(正規表現の例については、下部を参照してください)。長くてごめんなさい。

$ find . -printf "%y %p\n"    # print the file type the first time FYI
d .
f ./test
d ./dir1
d ./dir1/test
f ./dir1/test/file
f ./dir1/test/test
d ./dir1/scripts
f ./dir1/scripts/myscript.pl
f ./dir1/scripts/myscript.sh
f ./dir1/scripts/myscript.py
d ./dir2
d ./dir2/test
f ./dir2/test/file
f ./dir2/test/myscript.pl
f ./dir2/test/myscript.sh

$ find . -name test
./test
./dir1/test
./dir1/test/test
./dir2/test

$ find . -prune
.

$ find . -name test -prune
./test
./dir1/test
./dir2/test

$ find . -name test -prune -o -print
.
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

$ find . -regex ".*/my.*p.$"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test/myscript.pl

$ find . -name test -prune -regex ".*/my.*p.$"
(no results)

$ find . -name test -prune -o -regex ".*/my.*p.$"
./test
./dir1/test
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py

$ find . -not -regex ".*test.*"                   .
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

あなたはまた、「タッチ./dir1/scripts/test」(すなわち、そのプリントアウトサブディレクトリに、dirの「テスト」ファイルを持っている、としない)、それはでprintd得ることはありません場合find . -name test -prune -o -print:IOWは、-pruneまた、そのアクションでありますファイルでの作業
Olivier Dulac

10

他の回答で与えられたアドバイスに追加します(返信を作成する担当者がいません)...

-prune他の式と組み合わせる場合、使用する他の式によって動作に微妙な違いがあります。

@Laurence Gonsalvesの例では、「。snapshot」ディレクトリの下にない「* .foo」ファイルが見つかります:-

find . -name .snapshot -prune -o -name '*.foo' -print

ただし、このわずかに異なる省略形は、おそらく誤って、.snapshotディレクトリー(およびネストされた.snapshotディレクトリー)もリストします。

find . -name .snapshot -prune -o -name '*.foo'

理由は(私のシステムのマンページによると):-

指定された式にプライマリ、-exec、-ls、-ok、または-printが含まれていない場合、指定された式は実質的に次のものに置き換えられます。

(given_expression)-print

つまり、2番目の例は次のように入力して、用語のグループを変更することと同じです。

find . \( -name .snapshot -prune -o -name '*.foo' \) -print

これは少なくともSolaris 5.10で見られます。約10年間、* nixのさまざまなフレーバーを使用してきたので、これが発生する理由を最近検索しました。


を使用-pruneする場合と使用しない場合の違いにご注意いただきありがとうございます-print
mcw

3

Pruneは、どのディレクトリスイッチでも再帰しま​​せん。

マニュアルページから

-depthが指定されていない場合、true。ファイルがディレクトリの場合、その中に降りないでください。-depthが指定されている場合、false。無効。

基本的には、サブディレクトリには行きません。

この例を見てみましょう:

次のディレクトリがあります

  • / home / test2
  • / home / test2 / test2

実行するとfind -name test2

両方のディレクトリを返します

実行するとfind -name test2 -prune

/ home / test2を検索して/ home / test2 / test2を検索しないため、/ home / test2のみを返します。


100%正しいわけではありません。「条件に一致する場合はプルーニングを実行し、それがディレクトリの場合は、to-doリストから削除してください。つまり、入力しないでください」。-pruneはファイルに対しても機能します。
Olivier Dulac 2013年

2

私はこれについての専門家ではありません(このページはhttp://mywiki.wooledge.org/UsingFindとともに非常に役に立ちました)

気づいたの-pathは、すべてのベース名に一致する(これらの例では)直後の文字列/パスに完全に一致するパスの場合ですfind.-name

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

現在のディレクトリの.gitディレクトリをブロックしますでの発見と同様.

find . -name .git  -prune -o -name file  -print

すべての.gitサブディレクトリを再帰的にブロックします。

./ 重要なことに注意してください!! -pathアンカーされたパス. または一致するパスに一致する必要があります(またはor ' -o'の反対側から)それと一致する場合、除去されない可能性があります!私はこれに気付かなかったので、同じベース名のすべてのサブディレクトリを削除したくない場合に-pathを使用することになりました:D


あなたがしていることが言うなら、find bla/あなたは-path bla/.git を必要とするでしょう(または、あなた*が前にaを押し込んだ場合、代わりに-nameのように動作します)
sabgenton

1

dir自体を含むすべてを表示しますが、長い退屈なコンテンツは表示しません。

find . -print -name dir -prune

0

ここで良い答えをすべて読んだ場合、私の理解は次のすべてが同じ結果を返すということです:

find . -path ./dir1\*  -prune -o -print

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

find . -path ./dir1\*  -o -print
#look no prune at all!

しかし、最後のものはdir1のすべてを検索するため、かなり時間がかかります。本当の問題は、-or不要な結果を実際に検索せずに除外する方法だと思います。

だから私はプルーンは過去のマッチをまともなものにせず、それを完了としてマークすることを意味すると思います...

http://www.gnu.org/software/findutils/manual/html_mono/find.html 「しかし、これは '-prune'アクションの効果によるものではありません(これは、それ以上の下降を防ぐだけで、確実ではありませんその項目は無視します。代わりに、この効果は '-o'の使用によるものです。「/」条件の左側は./src/emacsで成功しているので、右を評価する必要はありません-この特定のファイルについては、手作業( '-print')をまったく行いません。」


0

findファイルのリストを作成します。提供した述語をそれぞれに適用し、合格したものを返します。

-prune結果から除外することを意味するこの考えは、私を本当に混乱させました。除去せずにファイルを除外できます。

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

すべては-pruneありません検索の動作を変更しています。現在の一致がディレクトリの場合は、「ちょっとfind、一致したファイルはそこに降りないでください」と表示されます。検索するファイルのリストからそのツリー(ファイル自体ではなく)を削除するだけです。

名前を付ける必要があります-dont-descend


0

かなりの数の答えがあります。それらのいくつかは少し理論的に重いです。なぜ私が一度プルーンを必要としたのかを残しておきますので、多分最初に必要な/例の種類の説明が誰かに役立つでしょう:)

問題

約20のノードディレクトリを持つフォルダがあり、それぞれにnode_modules期待どおりのディレクトリがあります。

プロジェクトに入ると、それぞれが表示されます../node_modules/module。しかし、あなたはそれがどうであるか知っています。ほとんどすべてのモジュールには依存関係があるため、あなたが見ているものはより似ていますprojectN/node_modules/moduleX/node_modules/moduleZ...

私は依存関係の依存関係を持つリストに溺れたくありませんでした...

-d n/を知って-depth nいても、各プロジェクトに必要なmain / first node_modulesディレクトリが次のように異なる深さであったため、それは私を助けませんでした:

Projects/MysuperProjectName/project/node_modules/...
Projects/Whatshisname/version3/project/node_modules/...
Projects/project/node_modules/...
Projects/MysuperProjectName/testProject/november2015Copy/project/node_modules/...
[...]

最初に最初で終わるパスのリストを取得node_modulesし、次のプロジェクトに移動して同じようにするにはどうすればよいですか?

入る -prune

を追加し-pruneても、標準の再帰検索が行われます。それぞれの「パス」が分析され、すべての検索結果が吐き出されfind、良いチャップのように掘り下げていきます。しかし、それnode_modulesは私が望んでいないものをさらに掘り下げることです。

だから、違いは、これらの異なるパスのいずれかに、ということである-pruneだろうfind、それはあなたの商品を見つけたとき、その特定の道のさらに下に掘り停止します。私の場合、node_modulesフォルダです。

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