
次のような問題があります。ディレクトリ構造があり、 という名前のディレクトリ内にあるものをすべて削除したいのですCaches
が、 という名前のディレクトリ以外はすべて削除する必要がありますSnapshots
。 でこれを行う方法がわかりません。探すまたは私が知っている他のコマンド。
私が質問する理由: iOS では、すべてのアプリに独自のキャッシュ ディレクトリがあります。アプリによっては、キャッシュが適切にクリアされないことがあります。この回答の解決策を使用すると、デバイスのドライブが別のコンピューターにマウントされている場合 (たとえば、FUSE (iExplorer) を使用)、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
という 1 つのフォルダを除くディレクトリ内のすべてを削除するだけであれば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
最後に追加します。
1つの注意点は、これによりファイル名前は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 はファイル パスに出現できない唯一のバイトであるため)、perl
の-n
with-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" ]]
。 のように正規表現の一致を否定する演算子がないため、前のコマンドが失敗した場合 (ディレクトリ名に Snapshots が含まれていない場合など) は を実行してい!=~
ました。||
rm
これは を使用する最新のシステムであればどれでも実行できますbash
が、 が必要ですbash
。また、ディレクトリ構造をいじる必要があるかもしれませんが、これで十分でしょう。
答え4
最初の部分: キャッシュという名前のディレクトリを見つけて、それに対して何かを行う
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
では、これらを組み合わせてみましょう。
find . -name Caches -type d -exec
find {} -depth -name Snapshots -type d -prune \
-o \( -type d -empty -o ! -type d \) -delete