特定のサブディレクトリを除くすべてのファイルを削除するには、検索を使用します。

特定のサブディレクトリを除くすべてのファイルを削除するには、検索を使用します。

aサブフォルダ内のすべてのファイルを除いて、特定の期間にフォルダにアクセスしなかったすべてのファイルを繰り返し削除したいと思いますb

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

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

find:-delete操作は自動的に-deepを有効にしますが、-pruneは-deepが適用されている間は何もしません。続行するには、-lengthオプションを明示的に使用してください。

-depth追加すると、すべてのファイルが含まれます。bいいえ発生する。

これを行う安全な方法を知っている人はいますか?

答え1

1つの方法は-exec rm代わりに使用することです-delete

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

または-not -path代わりに使用してください-prune

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

なぜ-prune以下と競合するのかを説明してください-delete

ヒントを与えて作成することはうまくいかないので、withを使用しようとすると-delete苦情がわかります。-prune-delete-depth-depth-prune

以下を使用または使用せずに find 動作を観察します-depth

$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2

単一のディレクトリ内の順序は保証されません。ただし、ディレクトリはコンテンツの前に処理されます。foo/beforefoo/*foo/barbeforeを参照してくださいfoo/bar/*

これは元に戻すことができます-depth

$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/

現在がfoo/*beforeの前に来ていることに注意してくださいfoo/。と同じですfoo/bar

さらなる説明:

  • -prunefind がディレクトリに降りるのを防ぎます。つまり、-pruneディレクトリの内容をスキップします。あなたの場合、-name b -pruneこれは、 find がその名前のディレクトリに到達すると、すべてのbサブディレクトリを含むそのディレクトリをスキップすることを意味します。
  • -depthfindにディレクトリ自体の前にディレクトリの内容を処理させます。これは、findがディレクトリエントリの処理を開始したときにbその内容がすでに処理されていることを意味します。したがって、-prune無効で-depth有効です。
  • -deleteつまり、-depthコンテンツを最初に削除してから空のディレクトリを削除できます。-delete空でないディレクトリの削除を拒否します。

代替方法の説明:

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*"。これは読者に練習問題として残す。

私はあなたがaandをbプレースホルダとして使用しており、実際の名前はallosaurusandに近いと仮定しますbrachiosaurus。これを置き換えると、誤brachiosaurus検出bの数が大幅に減少します。

少なくとも偽の肯定は次のとおりです。いいえあまりにも悲惨でないように削除しました。また、最初にコマンドなしでコマンドを実行し-delete(暗黙的なコマンドを入力する必要があります-depth)、出力を調べて誤検出を確認することもできます。

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

答え2

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

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

答え3

上記の答えと説明は非常に役立ちます。

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

「-not path」ソリューションの明らかなオーバーヘッドは、除外されたディレクトリとその下にあるすべてのファイルを表示することです。

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

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

「find -delete」はシステムコールを実行します。

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

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

(ワインモードオン(申し訳ありません))

-length、-delete、および-pruneの間の対話設計は、「-pruneディレクトリにあるファイル以外のファイルを削除する」という一般的な操作を実行する最も効率的な方法を不必要に削除したようです。

"-type f -delete"の組み合わせはディレクトリの削除を試みないため、-deepなしで実行できる必要があります。または、「find」に「-deletefile」操作がある場合(ディレクトリを削除しないことを意味)、-深さを暗示する必要はありません。

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

(ワインモードオフ)

関連情報