Löschen Sie das übergeordnete Verzeichnis (nicht leer), wenn ein bestimmtes untergeordnetes Verzeichnis leer ist

11

Ich muss das gesamte Verzeichnis, das Dateien enthält, in einem bestimmten Unterverzeichnis behalten, aber zum Löschen alle Verzeichnisse löschen, in denen das Unterverzeichnis leer ist.

Genauer gesagt ist hier die Struktur:

A
|
|--------312311
|       |
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|
|--------453453
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------566532
|       |----Recording
|       |----a.txt
|       |----b.txt

Die Unterverzeichnisse können eine Datei enthalten oder nicht. Ich muss also das gesamte Verzeichnis wie '312311' & '566532' löschen und nur '453453' sollte mit allen Daten belassen werden, da sich eine Datei im Ordner 'Aufnahme' befindet, die für mich ein bestimmtes Verzeichnis ist.

Ich habe viele Beiträge gesehen, aber es enthält Links zu vielen bestimmten Dateinamen. Jede Hilfe wird sehr geschätzt, da ich viele Male in der Woche tun muss.

Derek James
quelle
Befindet sich die Aufnahme immer auf der ersten Ebene im Verzeichnis? Außerdem: Befinden sich alle Ordner auf der ersten Ebene im Hauptverzeichnis?
Jacob Vlijm
A ist das Verzeichnis der obersten Ebene, in dem es nummerierte Verzeichnisse enthält. Und in den nummerierten Verzeichnissen enthält es den Ordner 'Recording' sowie einige 'txt'-Dateien wie z. Und in 'Aufnahme' kann es Dateien enthalten oder nicht ..
Derek James
Entfernen Sie das Bild Ihres Textes und fügen Sie den eigentlichen Text in Ihre Frage ein. Bilder von Text sind für uns umständlich zu verarbeiten. Die Verwendung des eigentlichen Textes ist unter anderem wesentlich bequemer.
LD James
Ich habe das gleiche von dir gefragt James ..
Derek James

Antworten:

12

Das folgende Skript funktioniert genau so, wie Sie es beschreiben:

  1. listet die Ordner in einem Verzeichnis auf
  2. Sucht in jedem Ordner nach einem Ordner mit dem Namen "Aufnahme".

    • Wenn es existiert und leer ist, löscht es seinen übergeordneten Ordner
    • Wenn es nicht vorhanden ist, wird auch der übergeordnete Ordner gelöscht
    • Dateien auf der ersten Ebene in A werden nicht gelöscht.

In einem Bild:

A
|
|--------123456
|       |
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|
|--------635623
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------123456
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|--------Monkey.txt

wird darin enden, dass:

A
|
|
|--------635623
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------Monkey.txt

Das Skript

#!/usr/bin/env python3
import os
import sys
import shutil

dr = sys.argv[1]

def path(*args):
    return os.path.join(*args)

for d in os.listdir(dr):
    try:
        if not os.listdir(path(dr, d, "Recording")):
            shutil.rmtree(path(dr,d))
    except FileNotFoundError:
        shutil.rmtree(path(dr,d))
    except NotADirectoryError:
        pass

Benutzen

  1. Kopieren Sie das Skript in eine leere Datei und speichern Sie es unter delete_empty.py
  2. Führen Sie es mit dem Verzeichnis (full!) (Enthält Ihre Unterverzeichnisse, A in Ihrem Beispiel) als Argument mit dem folgenden Befehl aus:

    python3 /path/to/delete_empty.py /path/to/directory
    

Das ist es.

Erläuterung

Den Inhalt Ihres Ordners "A" in das Skript einspeisen,

os.listdir(dr)

listet seine Unterverzeichnisse (und Dateien) auf. Dann:

if not os.listdir(path(dr, d, "Recording"))

wird versuchen, den Inhalt jedes der (Unter-) Ordner aufzulisten, was einen Fehler auslöst, wenn das Element eine Datei ist:

except NotADirectoryError
    pass

oder wenn der Ordner "Aufnahme" überhaupt nicht existiert:

FileNotFoundError
    shutil.rmtree(path(dr,d))

Wenn der Ordner "Aufnahme" vorhanden und leer ist, wird der übergeordnete Ordner entfernt:

if not os.listdir(path(dr, d, "Recording")):
    shutil.rmtree(path(dr,d))

BEARBEITEN

Zusätzlich, wie in Kommentaren angefordert, eine Version, die nach mehreren Unterverzeichnissen (Namen) sucht.

Im Fall enthält das Verzeichnis jede der aufgeführten (un- leer) subdirs, wird das Verzeichnis gehalten. Sonst wird es gelöscht.

Benutzen

  1. Kopieren Sie das Skript in eine leere Datei und speichern Sie es unter delete_empty.py
  2. Führen Sie es mit dem Verzeichnis (full!) (Enthält Ihre Unterverzeichnisse, in Ihrem Beispiel A) und den Namen der Unterverzeichnisse als Argumente mit dem folgenden Befehl aus:

    python3 /path/to/delete_empty.py /path/to/directory <subdir1> <subdir2> <subdir3>
    

Das ist es.

Das Skript

#!/usr/bin/env python3
import shutil
import os
import sys

dr = sys.argv[1]; matches = sys.argv[2:]

def path(*args):
    return os.path.join(*args)

for d in os.listdir(dr):
    # delete directory *unless* either one of the listed subdirs has files
    keep = False
    # check for each of the listed subdirs(names)
    for name in matches:
        try:
            if os.listdir(path(dr, d, name)):
                keep = True
                break
        except NotADirectoryError:
            # if the item is not a dir, no use for other names to check
            keep = True
            break
        except FileNotFoundError:
            # if the name (subdir) does not exist, check for the next
            pass
    if not keep:
        # if there is no reason to keep --> delete
        shutil.rmtree(path(dr,d))

Hinweis

Bitte führen Sie zuerst ein Testverzeichnis aus, um sicherzustellen, dass es genau das tut, was Sie wollen.

Jacob Vlijm
quelle
Dieser Code hat wirklich geholfen und es hat wie gesagt funktioniert. Danke für den Code. Wirklich hilfreich.
Derek James
Angenommen, wenn ich zwei oder mehr Ordner behalten und überprüfen muss, wie kann ich dies in diesem Code tun? Hinzufügen von 'OR' oder Pipe '| 'irgendwo .. schlagen Summe vor!
Derek James
Hallo @DerekJames, für die nur eine geringfügige Änderung erforderlich ist, werde ich heute Nachmittag veröffentlichen.
Jacob Vlijm
@Derek, warte, sollte der übergeordnete Ordner entfernt werden, wenn einer der Ordner leer ist oder alle? Könnte es mehrere von ihnen in einem übergeordneten Verzeichnis geben?
Jacob Vlijm
Angenommen, @Jacob, ich habe zwei Ordner 'Aufnahme' und 'Video'. Es sollte beide überprüfen. Wenn einer der Unterordner die Datei enthält, darf der Ordner '635623' nicht gelöscht werden. Und auch die Möglichkeit, weitere Ordner hinzuzufügen, um zu überprüfen, ob dies möglich ist.
Derek James
11

Verwenden von findund xargs:

find A -type d -name 'Recording' -empty -printf '%h\0' | xargs -0 echo rm -rf

(Entfernen Sie das, echosobald Sie sicher sind, dass es die richtigen Verzeichnisse identifiziert). Der printf '%h\0Teil druckt das (nullterminierte) übergeordnete Verzeichnis - von man find:

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

Bsp.: Gegeben

$ tree A
A
├── 312311
│   ├── a.txt
│   ├── b.txt
│   └── Recording
├── 453453
│   ├── a.txt
│   ├── b.txt
│   └── Recording
│       └── a.mp3
└── 566532
    ├── a.txt
    ├── b.txt
    └── Recording

6 directories, 7 files

dann

$ find A -type d -name 'Recording' -empty -printf '%h\0' | xargs -0 rm -rf
$ 
$ tree A
A
└── 453453
    ├── a.txt
    ├── b.txt
    └── Recording
        └── a.mp3

2 directories, 3 files
Steeldriver
quelle
finde A-Typ d-Name 'Aufnahme' -leer -printf '% h \ 0' | xargs -0 echo rm -rf dies druckt nur "rm -rf" UND findet A-Typ d -name 'Aufnahme' -leer -druckf '% h \ 0' | xargs -0 rm -rf funktioniert nicht ... Mache ich etwas falsch ..
Derek James
@DerekJames Sie müssen A durch das tatsächliche Verzeichnis ersetzen.
Jacob Vlijm
Wäre es in Ordnung, anstelle des Aufzeichnungsnamens einen regulären Ausdruck einzufügen, da das OP beispielsweise Dateinamen mit Nummern angegeben hat [\d]*?
George Udosen
@JacobVlijm: Ich habe durch das aktuelle Verzeichnis ersetzt, aber immer noch nicht wrking?
Derek James
@DerekJames das ist seltsam! es hat auf meinem System funktioniert, aber Sie haben vielleicht vergessen, zuerst in das Verzeichnis zu cd? Warten Sie, das sollte keine Rolle spielen ...
Jacob Vlijm
3

Hier ist eine einfachere Bash-Lösung:

for d in */; do rmdir "$d/Recording" && rm -r "$d"; done

Es funktioniert, weil rmdires fehlschlägt, wenn das Verzeichnis nicht leer ist, und &&verhindert , dass das Verzeichnis rm -rausgeführt wird, wenn rmdires nicht erfolgreich ist. Der Glob */stellt sicher, dass Sie nur an den Verzeichnissen arbeiten, damit andere Dateien nicht betroffen sind.

JoL
quelle
Schlaues Denken! +1
Jacob Vlijm