
Ich habe folgendes Problem. Ich habe eine Verzeichnisstruktur und möchte alles löschen, was sich in einem Verzeichnis namens befindet Caches
. Alles außer allen Verzeichnissen mit dem Namen sollte gelöscht werden Snapshots
. Ich kann nicht herausfinden, wie ich das mitfindenoder jeden anderen Befehl, den ich kenne.
Der Grund für meine Frage: Unter iOS hat jede App ihr eigenes Cache-Verzeichnis. Diese werden je nach App manchmal nicht richtig geleert. Mit der Lösung zu dieser Antwort könnte man Caches unter iOS leeren und so den Speicherplatz optimieren, wenn das Laufwerk des Geräts auf einem anderen Computer gemountet ist, z. B. mit FUSE (iExplorer).
Das habe ich bisher:
find . 2>/dev/null -type d -name "Caches" -maxdepth 3 -print
Das Ergebnis ist etwa:
./Library/Caches
Wenn ich das mache, ls ./Library/Caches
sehe ich den gesamten Inhalt und das Verzeichnis, das ich ausschließen möchte, da ich letztendlich alles außer diesem Snapshots
möchte .-delete
Ich möchte so etwas:
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
Antwort1
./Library/Caches
Ich bin etwas verwirrt von der Formulierung der Frage. Wenn Sie alles im Verzeichnis außer einem einzelnen Ordner namens löschen möchten Snapshots
, müssen Sie nicht verwenden find
. In bash
sind Shell-Globs der einfachste Weg:
shopt -s extglob # probably already enabled
echo Library/Caches/!(Snapshots)
Wenn dadurch alle Dateien/Verzeichnisse ausgedruckt werden, die Sie löschen möchten, ersetzen Sie echo
durch rm -f --
.
Snapshots
Wenn es mehrere Verzeichnisse auf verschiedenen Ebenen des darunter liegenden Verzeichnisbaums gibt ./Library/Caches
, die Sie beibehalten möchten, find
können Sie mit GNU Folgendes tun:
find Library/Caches ! -path '*Snapshots*'
Dies sollte alle Dateien/Verzeichnisse drucken, mit Ausnahme derer, die Snapshots
in ihrem Pfad enthalten sind. Es schließt Verzeichnisse ein, die Snapshots
Verzeichnisse enthalten (oder deren untergeordnete Verzeichnisse enthalten), find ... -delete
löscht diese jedoch nicht und gibt stattdessen eine Fehlermeldung aus, dass sie nicht leer sind. Wenn Sie zufrieden sind, fügen Sie sie -delete
am Ende hinzu.
Eine Einschränkung besteht darin, dass dadurchDateienbenannt Snapshots
intakt. Wenn dies ein Problem ist, gehen Sie stattdessen wie folgt vor:
find Library/Caches \( ! -path '*Snapshots*' -o -type f -name Snapshots \)
Wenn Sie zufrieden sind, fügen Sie es erneut hinzu -delete
.
Antwort2
find . -depth -print0 | perl -0lne '
if ("$_/" =~ m{/Caches(/.*)}s && $1 !~ m{/Snapshots/}) {rmdir $_ or unlink $_}'
Wenn Ihr find
nicht unterstützt -print0
, können Sie es durch ersetzen -exec printf '%s\0' {} +
.
Die Idee besteht darin, die Liste der Dateien mit NUL-Terminierung auszudrucken (da 0 das einzige Byte ist, das in einem Dateipfad nicht vorkommen kann) und die Option „ mit perl
“ zu verwenden , um für jeden dieser Dateinamen Code auszuführen (wobei der Dateiname auf „gesetzt“ gesetzt ist).-n
-0
$_
Mit -depth
werden Dateien vor ihrem übergeordneten Verzeichnis gedruckt. Wir entfernen nur Dateien oder Verzeichnisse (vorausgesetzt, sie sind leer, weshalb es wichtig ist, die Liste der depth
Reihe nach abzuarbeiten), deren Pfad /Caches/
nicht gefolgt von enthält /Snapshosts/
.
Antwort3
Ich bin kein find
Zauberer und möchte daher nicht behaupten, dass es mit nicht geht find
, aber ich weiß, dass es mit ein paar Zeilen geht bash
. Vorausgesetzt, ich verstehe Ihre Verzeichnisstruktur richtig:
#!/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
Die for
Anweisung gibt jedes Element in zurück Library/Caches/
. Die if [[ -d "$i" ]]
Anweisung prüft, ob jedes Element ein Verzeichnis ist, und wenn ja, wird sein Name geprüft, um festzustellen, ob er „Snapshots“ enthält [[ "$i" =~ "Snapshots" ]]
. Da es keinen Operator gibt, um eine Regex-Übereinstimmung zu negieren, wie !=~
, habe ich es früher ||
ausgeführt rm
, wenn der vorherige Befehl nicht erfolgreich war, z. B. wenn der Verzeichnisname keine Snapshots enthält.
Dies läuft auf jedem modernen System mit bash
, muss aber über verfügen bash
. Möglicherweise müssen Sie auch mit der Verzeichnisstruktur herumspielen, aber das sollte für Sie genügen.
Antwort4
Erster Teil: Verzeichnisse mit dem Namen Caches finden und etwas damit machen
find . -name Caches -type d -exec … \;
Zweiter Teil: Durchlaufen Sie ein Cache-Verzeichnis und entfernen Sie alles, behalten Sie jedoch Snapshots
Unterverzeichnisse und deren Inhalt (sowie die dorthin führenden Pfade). Führen Sie eine Tiefensuche durch, damit Verzeichnisse gelöscht werden können, sobald sie leer sind.
find /path/to/Caches -depth -name Snapshots -type d -prune \
-o \( -type d -empty -o ! -type d \) -delete
Kombinieren Sie sie nun miteinander.
find . -name Caches -type d -exec
find {} -depth -name Snapshots -type d -prune \
-o \( -type d -empty -o ! -type d \) -delete