特定のサブディレクトリを除くすべてのファイルを、findで削除します。


11

aサブフォルダー内のすべてのファイルを除いて、フォルダー内でしばらくアクセスされなかったすべてのファイルを再帰的に削除したいb

find a \( -name b -prune \) -o -type f -delete

ただし、エラーメッセージが表示されます。

find:-deleteアクションは-depthを自動的にオンにしますが、-depthが有効な場合、-pruneは何もしません。とにかく続行したい場合は、明示的に-depthオプションを使用してください。

追加する-depthと、すべてのファイルbが含まれますが、これ発生してはなりません。

誰もがこれを機能させる安全な方法を知っていますか?


@MichaelKjörling:私はextglobを見ていたが、どのように下にすべて含まれますa除いてはa/b
2013

動かないのcd a && ls -d !(b/*)?(ただ、それを行うためにrm -rではなくls -d。)
からCVn

あなたの提案はサブフォルダを削除します。フォルダをそのままにしたいのですが。の下のツリー内のすべてのファイルを検索して削除したいa(の下のファイルを除くa/b)。
2013

したがって、-rrmをスキップしてください。あなたが尋ねていることは、bashの拡張されたグロビングを使用することでかなり簡単に答えられるようで、グロビングの結果をどうするかはあなた次第です。
CVn 2013

@MichaelKjörling2つの問題が漠然としたソリューションを持っているからといって、質問が重複するわけではありません。2つの問題のそれぞれに対するほとんどの解決策は、他の問題を解決しません。
Gilles 'SO-悪をやめる'

回答:


13

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です。

より長い答え:

  • -prunefindがディレクトリに降りないようにします。つまり-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*"。それは読者のための練習問題として残されています。

私はあなたがプレースホルダーとして使用ab、本名がallosaurusandに似ていると思いbrachiosaurusます。brachiosaurus代わりに置くとb、誤検知の量が大幅に減少します。

少なくとも誤検知は削除されないので、それほど悲劇的ではありません。さらに、最初にコマンドを実行せずに-delete(ただし、暗黙のを配置することを忘れないで)、誤出力をチェックし-depth、出力を調べることができます。

find a -not -path "*/b*" -type f -depth

-not -pathただのものでした!寛大な説明をありがとう!
2013

1
なぜ-not -path機能するのか、なぜ機能-pruneしないのかについての詳細な説明は役に立ちます。と-not -path共存できるのはなぜ-depthですか?
Faheem Mitha

3

rm代わりに使用してください-delete

find a -name b -prune -o -type f -exec rm -f {} +

1
rm機能する理由とdelete機能しない理由について詳しく説明していただけますか?
Faheem Mitha、2015

1
ああ、たぶん "-deleteは空でないディレクトリの削除を拒否する"ためか、@ lesmanaを引用しています。したがって、空でないディレクトリの削除を拒否します。しかしrm、その問題はありません。しかし、とにかく、精緻化は良いことです。
Faheem Mitha、2015

@FaheemMitha、その答えは質問にあります。-delete-depth、とは明らかに機能しません-prune-path動作しますが、find探索する必要のないディレクトリに降りることはできます。
ステファンChazelas

0

上記の回答と説明は非常に役に立ちました。

「-exec rm {} +」または「-not -path ... -delete」の回避策を使用していますが、「find ... -delete」よりもはるかに遅くなる可能性があります。「find ... -delete」は、NFSファイルシステムの深いディレクトリで「-exec rm {} +」より5倍速く実行されます。

「-not path」ソリューションには、除外されたディレクトリ以下のすべてのファイルを確認するオーバーヘッドがあります。

"find .. -exec rm {} +"は、システムコールを実行するrmを呼び出します。

fstatat(AT_FDCWD, path...); 
unlinkat(AT_FDCWD, path, 0)

「検索-削除」はシステムコールを実行します。

 fd=open(dir,...);
 fchdir(fd); 
 fstatat(AT_FDCWD, filename,...)
 unlinkat(dirfd, filename,...)

したがって、「-exec rm {} +」rmコマンドは、ファイルごとに2回iノードルックアップへのフルパスを実行しますが、「find -delete」は、現在のディレクトリ内のファイル名の統計とリンク解除を実行します。1つのディレクトリから多数のファイルを削除する場合、これは大きな利点です。

(泣き声モードがオン(申し訳ありません))

-depth、-delete、および-prune間の相互作用の設計は、一般的なアクション「-pruneディレクトリーにあるファイル以外のファイルを削除する」を実行する最も効率的な方法を不必要に排除しているようです

「-type f -delete」の組み合わせは、ディレクトリを削除しようとしないため、-depthなしで実行できるはずです。または、「検索」に「ディレクトリを削除しない」という「-deletefile」アクションがあった場合、-depthを暗黙的に指定する必要はありません。

フルパスのリンクを解除する代わりに、rmがファイル名をソートし、ディレクトリを開き、unlinkat(dir_fd、filename)を実行するオプションがある場合、rmコマンドへのxargsまたはfind -exec呼び出しが高速化される可能性があります。-rオプションを使用してディレクトリを再帰的に処理する場合、すでにunlinkat(dir_fd、filename)を実行しています。

(鳴き声モードオフ)

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