Leere Verzeichnisse finden UNIX

90

Ich muss leere Verzeichnisse für eine bestimmte Liste von Verzeichnissen finden. Einige Verzeichnisse enthalten Verzeichnisse.

Wenn interne Verzeichnisse ebenfalls leer sind, kann ich sagen, dass das Hauptverzeichnis leer ist, andernfalls ist es nicht leer.

Wie kann ich das testen?

Beispielsweise:

A>A1(file1),A2 this is not empty beacuse of file1
B>B1(no file) this is empty
C>C1,C2 this is empty
soField
quelle
2
Ich denke, Martins Antwort ist hier am besten geeignet. Die aktuell akzeptierte Antwort ist nur ein unvollständiger Pseudocode.
Léo Léopold Hertz 23

Antworten:

34

Überprüfen Sie, ob find <dir> -type fetwas ausgegeben wird. Hier ist ein Beispiel:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done
Marcelo Cantos
quelle
2
Nein, es werden keine Unterverzeichnisse ausgegeben. Dafür ist das da -type f.
Marcelo Cantos
Wenn jedoch leere Dateien vorhanden sind , wird die Meldung von Ihrer Lösung nicht angezeigt .
Yasir Arsanukaev
3
Yasir: Ich würde denken, dass ein Verzeichnis, das eine leere Datei enthält, selbst nicht leer ist. Wäre das nicht das richtige Ergebnis?
Ukko
2
@akostadinov: Wenn ich die vom OP angegebenen Verzeichnisse und Dateien erstelle - mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1- und den Code in meiner Antwort ausführe, wird gemeldet , dass B und C leer sind, wie vom OP gefordert. Sie müssen also etwas genauer sein als "es wird nicht funktionieren".
Marcelo Cantos
1
Wenn Sie ein Bash Noob wie ich sind, überprüfen Sie, was -z hier bedeutet .
OmarOthman
255

Es hängt ein wenig davon ab, was Sie mit den leeren Verzeichnissen machen möchten. Ich benutze den folgenden Befehl, wenn ich alle leeren Verzeichnisse innerhalb eines Baums löschen möchte , z test. B. Verzeichnis.

find test -depth -empty -delete

Bei dem obigen Befehl ist zu beachten, dass auch leere Dateien entfernt werden. Verwenden Sie daher die Option -type d , um dies zu vermeiden.

find test -depth -type d -empty -delete

Löschen -delete, um die übereinstimmenden Dateien und Verzeichnisse anzuzeigen.

Wenn Sie einen leeren Verzeichnisbaum so definieren, dass er keine Dateien enthält, können Sie etwas zusammenfügen, je nachdem, ob find test -type fetwas zurückgegeben wird.

find ist ein großartiges Dienstprogramm und RTFM früh und oft, um wirklich zu verstehen, wie viel es kann :-)

Martin
quelle
8
-delete impliziert -tiefe (zumindest für GNU findutils 4.4.2)
Dr. Person Person II
4
wusste nicht -empty, so bequem!
Raffi
2
Allerdings auf Maschinen, die nicht das neueste und beste Linux sind. (EG Solaris), dann haben Sie keine Lust, Funktionen wie -empty oder -delete zu finden.
Anthony
3
Führen Sie unter MacOS-X für fast leere Verzeichnisse find test -name ".DS_Store" -deletezuerst den -empty deleteBefehl und dann den Befehl aus. Beachten Sie auch, wie pushdim übergeordneten Verzeichnis, so dass find testwird find ., aber der Rest der Befehle sind die gleichen.
Olie
1
@Martin Können Sie bitte die Definition von -depthhier hinzufügen , dh Ursache finden, um eine Tiefenüberquerung durchzuführen, dh Verzeichnisse werden in Nachbestellung besucht und alle Einträge in einem Verzeichnis werden vor dem Verzeichnis selbst bearbeitet. Ich denke, dass es hier relevant ist.
Léo Léopold Hertz 23
48

Sie können den folgenden Befehl verwenden:

find . -type d -empty
mosg
quelle
1
-empty funktioniert nur, wenn das aktuelle Verzeichnis vollständig leer ist, nicht wenn der Teilbaum keine Dateien enthält.
Marcelo Cantos
@soField Getesteter Fund. -Typ d -leer mit FreeBSD & CentOS. Funktioniert gut. Was ist dein Betriebssystem?
Mosg
1
hp-ux also gibt es keinen leeren Parameter
soField
@soField Sie sehen also, dass es (für uns alle) besser ist, diese Daten oben auf Ihrer Frage zu veröffentlichen ...
Mosg
2
find hat auch unter Solaris -empty nicht, aber es hat -depth, um die Tiefendurchquerung zu erzwingen, sodass leere Unterverzeichnisse gelöscht werden können, bevor das übergeordnete Verzeichnis auf Leere überprüft wird.
Eirikma
26
find directory -mindepth 1 -type d -empty -delete

Dies ist die Version, die ich am interessantesten fand. Wenn es aus dem internen Verzeichnis ausgeführt wird , werden alle leeren Verzeichnisse unten gelöscht (ein Verzeichnis wird als leer betrachtet, wenn es nur leere Verzeichnisse enthält).

Die Option mindepth verhindert, dass das Verzeichnis selbst gelöscht wird, wenn es leer ist.

Dr. Person Person II
quelle
2
Sie können dies nachverfolgen rmdir --ignore-fail-on-non-empty -p directory, um auch die Eltern loszuwerden.
Pete Peterson
@Pete Peterson Mein Befehl scheint Verzeichnisse zu entfernen, die nur andere leere Verzeichnisse enthalten (was OP auch zu wollen scheint). Ich stelle fest, dass Ihr Befehl den Benutzer normalerweise in einem Verzeichnis mit einem fehlenden i-Knoten belässt, selbst wenn er das erreicht, was er will, was für ihn verwirrend sein kann. Vielleicht verpasse ich den Punkt.
Dr. Person Person II
23

find . -type d -empty

Findet und listet leere Verzeichnisse und Unterverzeichnisse im aktuellen Baum auf. ZB resultierende Liste von leeren Verzeichnissen und Unterverzeichnissen:

./2047
./2032
./2049
./2063
./NRCP26LUCcct1/2039
./NRCP26LUCcct1/2054
./NRCP26LUCcct1/2075
./NRCP26LUCcct1/2070

Für die Verzeichnisse wird keine Operation ausgeführt. Sie werden einfach aufgelistet. Das funktioniert bei mir.

user7194913
quelle
16

Finde einfach leere Verzeichnisse

Um nur leere Verzeichnisse zu finden (wie im Fragentitel angegeben), ist die Antwort des Mosg richtig:

find -type d -empty

Ist jedoch -emptymöglicherweise bei sehr alten findVersionen nicht verfügbar (dies ist beispielsweise bei HP-UX der Fall ). Wenn dies der Fall ist, lesen Sie die im folgenden Abschnitt beschriebenen Techniken. Ist ein Verzeichnis leer? .

Leere Verzeichnisse löschen

Das ist etwas schwierig: Angenommen, ein Verzeichnis MyDirenthält leere Verzeichnisse. Nach dem Entfernen dieser leeren Verzeichnisse MyDirwird ein leeres Verzeichnis und sollte auch entfernt werden. Daher verwende ich den Befehl rmdirmit der Option --parents(oder -p), die nach Möglichkeit auch übergeordnete Verzeichnisse entfernt:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} +

In älteren findVersionen wird die Anweisung +noch nicht unterstützt, daher können Sie ;stattdessen Folgendes verwenden :

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} `;`

Ist ein Verzeichnis leer?

In den meisten dieser Antworten wird erläutert, wie überprüft wird, ob ein Verzeichnis leer ist. Deshalb stelle ich hier die drei verschiedenen Techniken zur Verfügung, die ich kenne:

  1. [ $(find your/dir -prune -empty) = your/dir ]

    d=your/dir
    if [ x$(find "$d" -prune -empty) = x"$d" ]
    then
      echo "empty (directory or file)"
    else
      echo "contains files (or does not exist)"
    fi

    eine Variation:

    d=your/dir
    if [ x$(find "$d" -prune -empty -type d) = x"$d" ]
    then
      echo "empty directory"
    else
      echo "contains files (or does not exist or is not a directory)"
    fi

    Erläuterung:

    • find -pruneist ähnlich wie find -maxdepth 0mit weniger Zeichen
    • find -type d druckt nur Verzeichnisse
    • find -empty druckt die leeren Verzeichnisse und Dateien

      > mkdir -v empty1 empty2 not_empty
      mkdir: created directory 'empty1'
      mkdir: created directory 'empty2'
      mkdir: created directory 'not_empty'
      > touch not_empty/file
      > find empty1 empty2 not_empty -prune -empty
      empty1
      empty2
  2. (( ${#files} ))

    Dieser Trick ist 100% bash, ruft aber eine Sub-Shell auf (erzeugt sie). Die Idee stammt von Bruno De Fraine und wurde von teambob verbessert den Kommentar . Ich rate diesem, wenn Sie verwenden und wenn Ihr Skript nicht portabel sein muss.

    files=$(shopt -s nullglob dotglob; echo your/dir/*)
    if (( ${#files} ))
    then 
      echo "contains files"
    else 
      echo "empty (or does not exist or is a file)"
    fi

    Hinweis: Kein Unterschied zwischen einem leeren und einem nicht vorhandenen Verzeichnis (und selbst wenn der angegebene Pfad eine Datei ist).

  3. [ $(ls -A your/dir) ]

    Dieser Trick ist inspiriert von dem Artikel von nixCraft aus dem Jahr 2007. Andrew Taylor antwortete 2008 und gr8can8dian 2011.

    if [ "$(ls -A your/dir)" ]
    then
      echo "contains files"
    else
      echo "empty (or does not exist or is a file)"
    fi

    oder die einzeilige Bashism-Version:

    [[ "$(ls -A your/dir)" ]] && echo "contains files" || echo "empty or ..."

    Hinweis: ls Gibt zurück, $?=2wenn das Verzeichnis nicht vorhanden ist. Aber kein Unterschied zwischen einer Datei und einem leeren Verzeichnis.

olibre
quelle
rmdir -vphat mir sehr geholfen, da ich nicht nur alle leeren Verzeichnisse unter einem Stamm löschen musste, sondern nach dem Löschen einer Datei nach leeren Verzeichnissen und übergeordneten Verzeichnissen suchen musste. In meiner Situation sind leere Verzeichnisse in Ordnung, solange sie nicht im Baum enthalten sind, aus dem ich gerade eine Datei entferne. Vielen Dank!
Ethan Hohensee
2

Diese rekursive Funktion scheint den Trick zu tun:

# Bash
findempty() {
    find ${1:-.} -mindepth 1 -maxdepth 1 -type d | while read -r dir
    do
        if [[ -z "$(find "$dir" -mindepth 1 -type f)" ]] >/dev/null
        then
            findempty "$dir"
            echo "$dir"
        fi
    done
}

Angesichts dieses Beispiels Verzeichnisstruktur:

    .
    | - dir1 /
    | - dir2 /
    | `- dirB /
    | - dir3 /
    | `- dirC /
    | `- file5
    | - dir4 /
    | | - dirD /
    | `- file4
    `- dir5 /
        `- dirE /
            `- dir_V /

Das Ergebnis der Ausführung dieser Funktion wäre:

    ./dir1
    ./dir5/dirE/dir_V
    ./dir5/dirE
    ./dir5
    ./dir2/dirB
    ./dir2

was fehlt /dir4/dirD. Wenn Sie den rekursiven Aufruf findempty "$dir"nach dem verschieben fi, nimmt die Funktion dieses Verzeichnis in ihre Ergebnisse auf.

Bis auf weiteres angehalten.
quelle
2

Wie wäre es mit rmdir *? Dieser Befehl schlägt in nicht leeren Verzeichnissen fehl.

evandrix
quelle
Etwas, das ich manchmal getan habe, um allgemein aufzuräumen. Auch erledigte Dinge wie rmdir */*/* */* * Obwohl dies keine 'Punktdateien' behandelt, erwarten Sie in manuellen Situationen (Bereinigen von Datendateien) im Allgemeinen keine 'Punktdateien'. Die rekursiven Methoden dienen jedoch einer automatisierteren allgemeinen Bereinigung, insbesondere in sehr großen Verzeichnisstrukturen.
Anthony
In einem Fall war es komplizierter, da ich leere Verzeichnisse entfernen musste, wobei 'leer' Verzeichnisse enthielt, die eine einzelne 'Readme'-Datei enthalten konnten. Alles andere im Verzeichnis und es war nicht 'leer'. In diesem Beispiel umfasste die Verzeichnisstruktur Zehntausende von Unterverzeichnissen.
Anthony
1

Der folgende Befehl gibt 1 zurück, wenn ein Verzeichnis leer ist (oder nicht existiert) und andernfalls 0 (damit der Rückkehrcode !in einem Shell-Skript invertiert werden kann ):

find $dir -type d -prune -empty -exec false {} +
Mateusz Piotrowski
quelle
0

Ich habe eine einfache Struktur wie folgt erstellt:

test/
test/test2/
test/test2/test2.2/
test/test3/
test/test3/file

Das test/test3/fileenthält Junk-Text.

Die Ausgabe find test -emptygibt " test/test2/test2.2" als einziges leeres Verzeichnis zurück.

James Sumners
quelle
die op bittet um die Rückgabe von test / test2
Tatsächlich. Aber ich dachte, er könnte die Find-Manpage lesen, um weiter zu gehen. Ein Skript, das die Tiefen basierend auf den Ergebnissen anpasst, funktioniert einwandfrei.
James Sumners
Dies war die nützlichste Version für mich, danke
Andreas
0

Ein einfacher Ansatz wäre:

$ [ "$(ls -A /path/to/direcory)" ] && echo "not empty" || echo "its empty"

ebenfalls,

if [ "$(ls -A /path/to/direcory)" ]; then
   echo "its not empty"
else 
   echo "empty directory"
phoenix24
quelle
0
find . -name -type d -ls |awk '($2==0){print $11}'
Vijay
quelle