TL; DR:の-exec rm
代わりに使用するのが最善の方法です-delete
。
find a \( -name b -prune \) -o -type f -exec rm {} +
説明:
で使用しようとする-delete
と、なぜfindが文句を言うの-prune
ですか?
短い答え:-delete
暗示-depth
し-depth
て-prune
無効にするため。
長い回答をする前に、まずfindの有無によるfindの動作を観察します-depth
。
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
1つのディレクトリでの順序については保証されません。ただし、ディレクトリはその内容の前に処理されることが保証されています。foo/
何よりも前に、foo/*
そしてfoo/bar
何よりも前に注意してくださいfoo/bar/*
。
これはで元に戻すことができます-depth
。
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
すべてfoo/*
が以前に表示されることに注意してくださいfoo/
。と同じfoo/bar
です。
より長い答え:
-prune
findがディレクトリに降りないようにします。つまり-prune
、ディレクトリの内容をスキップします。あなたの場合-name b -prune
、findがという名前のディレクトリに下降するのを防ぎますb
。
-depth
ディレクトリ自体の前にディレクトリの内容を処理することを見つけます。つまり、findがディレクトリエントリを処理できるようになるまでに、b
その内容はすでに処理されています。したがって、効果-prune
はありませ-depth
ん。
-delete
-depth
最初にファイルを削除してから空のディレクトリを削除できることを意味します。-delete
空でないディレクトリの削除を拒否します。-delete
空ではないディレクトリを強制的に削除するオプションや-delete
、暗黙的に防止するオプションを追加することは可能だと思います-depth
。しかし、それは別の話です。
あなたが望むものを達成する別の方法があります:
find a -not -path "*/b*" -type f -delete
これは覚えやすいかもしれません。
このコマンドはまだディレクトリに降りて、それらを拒否するb
ためだけに-not
その中のすべてのファイルを処理します。ディレクトリb
が巨大な場合、これはパフォーマンスの問題になる可能性があります。
-path
とは動作が異なり-name
ます。はパス全体と一致し-name
ますが、(ファイルまたはディレクトリの)名前-path
とのみ一致します。たとえば、パスを観察します/home/lesmana/foo/bar
。-name -bar
名前がであるため一致しbar
ます。-path "*/foo*"
文字列/foo
がパスに含まれているため一致します。-path
使用する前に理解しておくべき複雑な点があります。find
詳細については、のマニュアルページを参照してください。
これは100%万能ではないことに注意してください。「誤検知」の可能性があります。上記のコマンドの記述方法では、名前がb
(ポジティブ)で始まる親ディレクトリを持つファイルはスキップされます。ただしb
、ツリー内の位置に関係なく、名前が先頭にあるファイルもすべてスキップします(誤検知)。これは、より優れた式を書くことで修正できます"*/b*"
。それは読者のための練習問題として残されています。
私はあなたがプレースホルダーとして使用a
しb
、本名がallosaurus
andに似ていると思いbrachiosaurus
ます。brachiosaurus
代わりに置くとb
、誤検知の量が大幅に減少します。
少なくとも誤検知は削除されないので、それほど悲劇的ではありません。さらに、最初にコマンドを実行せずに-delete
(ただし、暗黙のを配置することを忘れないで)、誤出力をチェックし-depth
、出力を調べることができます。
find a -not -path "*/b*" -type f -depth
a
除いてはa/b
?