find を使用してディレクトリを探し、ディレクトリを除くすべてのファイルを削除します。

find を使用してディレクトリを探し、ディレクトリを除くすべてのファイルを削除します。

次の問題があります。ディレクトリ構造があり、ディレクトリ内のすべてのエントリを削除したいと思いますCaches。名前付きのすべてのディレクトリを除いて、すべての内容を削除する必要がありますSnapshots。私はこれを行う方法がわからない探すそれとも、私が知っている他の命令でも。

私が尋ねる理由は、iOSの各アプリケーションに独自のCachesディレクトリがあるためです。アプリケーションによっては正しくクリアされない場合もあります。この回答のソリューションを使用すると、iExplorer(FUSE)を使用するなど、デバイスのドライブが別のコンピュータにマウントされたときにiOSでキャッシュを消去してディスク容量を最適化できます。

これが私が今まで持っているものです:

find . 2>/dev/null -type d -name "Caches" -maxdepth 3 -print

これにより、次のような内容が返されます。

./Library/Caches

私がするとき、私はls ./Library/CachesすべてのコンテンツとSnapshotsディレクトリを見て、最終的にそれ以外のすべてが欲しいので、それらを除外したいと思います-delete


私は次のようなものが欲しい:

  Before:                            After:

  .                                  .
  ├── a                              ├── a
  │   ├── a                          │   ├── a
  │   └── Caches                     │   └── Caches
  │       ├── a                      │       └── a
  │       │   └── Snapshots          │           └── Snapshots
  │       │       └── a              │               └── a
  │       ├── b                      └── b
  │       │   └── a                      └── c
  │       └── c                  
  └── b
      ├── c
      └── Caches
          ├── a
          │   └── foo
          │       └── a
          └── b
              └── a

答え1

質問の表現が少し混乱していますね。./Library/Caches名前付き単一フォルダを除いてディレクトリ内のすべてのエントリを削除したい場合は、シェルglobをSnapshots使用する必要がない最も簡単な方法は次のとおりです。findbash

shopt -s extglob  # probably already enabled
echo Library/Caches/!(Snapshots)

削除したいすべてのファイル/ディレクトリが印刷されたら、にecho置き換えますrm -f --

Snapshotsディレクトリツリーの異なるレベルに複数のディレクトリを維持するには、GNUを使用して次のことを実行できます。./Library/Cachesfind

find Library/Caches ! -path '*Snapshots*'

Snapshots これにより、パス内のファイル/ディレクトリを除くすべてのファイル/ディレクトリが印刷されます。これには、ディレクトリ(または含まれているサブディレクトリ)を含むディレクトリがSnapshots含まれますが、find ... -deleteそのディレクトリは削除されませんが空ではないというエラーが表示されます。満足したら、-delete最後に追加してください。

これにより、すべての項目が残ります。文書名前がよく指定されましたSnapshots。これが問題の場合は、次のように変更してください。

find Library/Caches \( ! -path '*Snapshots*' -o -type f -name Snapshots \)

幸せであるとき更に加えなさい-delete

答え2

find . -depth -print0 | perl -0lne '
  if ("$_/" =~ m{/Caches(/.*)}s && $1 !~ m{/Snapshots/}) {rmdir $_ or unlink $_}'

findサポートしていない場合-print0に置き換えることができます-exec printf '%s\0' {} +

アイデアは、NULで終わるファイルのリストを印刷し(0はファイルパスには現れない唯一のバイトなので)、オプション(filenameにperl設定)を使用して各ファイル名に対していくつかのコードを実行することです。-n-0$_

を使用すると、-depthファイルは親ディレクトリの前に印刷されます。ファイルやディレクトリdepthのパス/Caches//Snapshosts/

答え3

私はウィザードではないfindので、これを実行するために使用できないとは言いたくありませんが、find数行で完了できることを知っていますbash。あなたのディレクトリ構造を正しく理解していると仮定すると、次のようになります。

#!/bin/bash

for i in Library/Caches/*; do
    if [[ -d "$i" ]]; then
         [[ "$i" =~ "Snapshots" ]] ||  echo "rm-ing  $i" # change to rm -rf "$i" to use
    fi
done

このforステートメントはの各項目を返しますLibrary/Caches/。このif [[ -d "$i" ]]ステートメントは各エントリがディレクトリであることを確認し、その場合は名前に「Snapshots」が含まれていることを確認します[[ "$i" =~ "Snapshots" ]]。正規表現の一致を無効にする演算子がないため、以前の!=~コマンドが成功しなかった場合(ディレクトリ名にスナップショットが含まれていない場合など) ||rm

これは使用されているすべての最新システムで機能しますbashが、必ず機能する必要がありますbash。また、ディレクトリ構造で遊ぶ必要があるかもしれませんが、これはうまくいくでしょう。

答え4

パート1:キャッシュという名前のディレクトリを見つけていくつかのタスクを実行する

find . -name Caches -type d -exec … \;

パート2:キャッシュディレクトリを繰り返してすべてのエントリを削除しますが、サブSnapshotsディレクトリとそのコンテンツ(およびそのパス)は保持します。ディレクトリが空の場合は、削除できるように深さ優先の巡回を実行します。

    find /path/to/Caches -depth -name Snapshots -type d -prune \
                             -o \( -type d -empty -o ! -type d \) -delete

今、それらを1つにまとめます。

find . -name Caches -type d -exec
    find {} -depth -name Snapshots -type d -prune \
                -o \( -type d -empty -o ! -type d \) -delete

関連情報