Verwenden Sie „Find“, um ein bestimmtes Verzeichnis zu finden und alle darin enthaltenen Dateien außer einem Verzeichnis zu löschen.

Verwenden Sie „Find“, um ein bestimmtes Verzeichnis zu finden und alle darin enthaltenen Dateien außer einem Verzeichnis zu löschen.

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/Cachessehe ich den gesamten Inhalt und das Verzeichnis, das ich ausschließen möchte, da ich letztendlich alles außer diesem Snapshotsmö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/CachesIch 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 bashsind 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 echodurch rm -f --.

SnapshotsWenn es mehrere Verzeichnisse auf verschiedenen Ebenen des darunter liegenden Verzeichnisbaums gibt ./Library/Caches, die Sie beibehalten möchten, findkö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 SnapshotsVerzeichnisse enthalten (oder deren untergeordnete Verzeichnisse enthalten), find ... -deletelöscht diese jedoch nicht und gibt stattdessen eine Fehlermeldung aus, dass sie nicht leer sind. Wenn Sie zufrieden sind, fügen Sie sie -deleteam Ende hinzu.

Eine Einschränkung besteht darin, dass dadurchDateienbenannt Snapshotsintakt. 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 findnicht 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 -depthwerden Dateien vor ihrem übergeordneten Verzeichnis gedruckt. Wir entfernen nur Dateien oder Verzeichnisse (vorausgesetzt, sie sind leer, weshalb es wichtig ist, die Liste der depthReihe nach abzuarbeiten), deren Pfad /Caches/nicht gefolgt von enthält /Snapshosts/.

Antwort3

Ich bin kein findZauberer 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 forAnweisung 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 SnapshotsUnterverzeichnisse 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

verwandte Informationen