次の問題があります。ディレクトリ構造があり、ディレクトリ内のすべてのエントリを削除したいと思います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
使用する必要がない最も簡単な方法は次のとおりです。find
bash
shopt -s extglob # probably already enabled
echo Library/Caches/!(Snapshots)
削除したいすべてのファイル/ディレクトリが印刷されたら、にecho
置き換えますrm -f --
。
Snapshots
ディレクトリツリーの異なるレベルに複数のディレクトリを維持するには、GNUを使用して次のことを実行できます。./Library/Caches
find
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