Znajdowanie pustych katalogów UNIX

92

Muszę znaleźć puste katalogi dla podanej listy katalogów. Niektóre katalogi zawierają katalogi.

Jeśli katalogi wewnętrzne są również puste, mogę powiedzieć, że katalog główny jest pusty, w przeciwnym razie nie jest pusty.

Jak mogę to sprawdzić?

Na przykład:

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
źródło
2
Myślę, że odpowiedź Martina jest tutaj najbardziej odpowiednia. Aktualnie akceptowana odpowiedź to tylko niekompletny pseudokod.
Léo Léopold Hertz 준영

Odpowiedzi:

34

Sprawdź, czy find <dir> -type fcoś wyświetla. Oto przykład:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done
Marcelo Cantos
źródło
2
Nie, to nie wyświetli podkatalogów. Do tego -type fsłuży.
Marcelo Cantos
Jednak jeśli są puste pliki , rozwiązanie nie przyniesie wiadomości.
Yasir Arsanukaev
4
Yasir: Myślę, że katalog zawierający pusty plik z raną sam w sobie nie jest pusty. Czy to nie byłby właściwy wynik?
Ukko
2
@akostadinov: Jeśli utworzę katalogi i pliki zgodnie ze wskazaniami OP - mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1- i uruchomię kod w mojej odpowiedzi, zgłosi, że B i C są puste, zgodnie z wymaganiami OP. Będziesz więc musiał być bardziej szczegółowy niż „to nie zadziała”.
Marcelo Cantos
1
Jeśli jesteś Bash noobem jak ja, sprawdź, co oznacza -z tutaj .
OmarOthman
260

Zależy to trochę od tego, co chcesz zrobić z pustymi katalogami. Używam poniższego polecenia, gdy chcę usunąć wszystkie puste katalogi w drzewie, powiedzmy testkatalog.

find test -depth -empty -delete

Jedną rzeczą, na którą należy zwrócić uwagę w powyższym poleceniu, jest to, że usunie ono również puste pliki , więc użyj opcji -type d , aby tego uniknąć.

find test -depth -type d -empty -delete

Upuść, -deleteaby zobaczyć dopasowane pliki i katalogi.

Jeśli twoja definicja pustego drzewa katalogów jest taka, że ​​nie zawiera ono żadnych plików, możesz skleić coś razem w oparciu o to, czy find test -type fcoś zwraca.

find to świetne narzędzie, a RTFM wcześnie i często, aby naprawdę zrozumieć, ile może zrobić :-)

Jaskółka oknówka
źródło
8
-delete implikuje -depth (przynajmniej dla GNU findutils 4.4.2)
Dr Osoba II
4
nie wiedziałem -empty, tak wygodne!
Raffi
2
Jednak na komputerze, który nie jest najnowszym i najlepszym systemem Linux. (Np. Solaris), nie masz ochoty znaleźć funkcji takich jak -empty czy -delete.
anthony
3
W systemie MacOS-X, dla prawie pustych katalogów, uruchom find test -name ".DS_Store" -deletenajpierw, a następnie -empty deletepolecenie. Zwróć także uwagę, jak do pushdkatalogu nadrzędnego, więc stanie find testsię find ., ale reszta poleceń jest taka sama.
Olie
1
@Martin Czy możesz dodać definicję -depthtutaj, tj. Przyczyń się do znalezienia, aby wykonać przejście w głąb, tj. Katalogi są odwiedzane w kolejności końcowej i wszystkie wpisy w katalogu będą działały przed samym katalogiem. Myślę, że jest to istotne tutaj.
Léo Léopold Hertz 준영
50

Możesz użyć następującego polecenia:

find . -type d -empty
mosg
źródło
1
-empty działa tylko wtedy, gdy bieżący katalog jest całkowicie pusty, a nie wtedy, gdy poddrzewo nie zawiera żadnych plików.
Marcelo Cantos
@soField Tested find. -type d -empty z FreeBSD i CentOS. Działa w porządku. Jaki masz system operacyjny?
mosg
1
hp-ux, więc nie ma pustego parametru
soField
@soField Więc widzisz, że lepiej (dla nas wszystkich) umieścić te dane na początku twojego pytania ...
mosg
2
find nie ma również opcji -empty w systemie solaris, ale ma opcję -depth, aby wymusić przechodzenie w pierwszej kolejności w głąb, dzięki czemu puste podkatalogi można usunąć, zanim katalog nadrzędny zostanie sprawdzony pod kątem pustości.
eirikma
26
find directory -mindepth 1 -type d -empty -delete

To jest wersja, która była dla mnie najbardziej interesująca. Jeśli zostanie wykonany z wnętrza katalogu , usunie wszystkie puste katalogi poniżej (katalog jest uważany za pusty, jeśli zawiera tylko puste katalogi).

Opcja mindepth zapobiega usunięciu samego katalogu, jeśli jest on pusty.

Dr Osoba Osoba II
źródło
2
Możesz to rmdir --ignore-fail-on-non-empty -p directoryzrobić, aby pozbyć się również rodziców.
Pete Peterson
@Pete Peterson Wydaje się, że moje polecenie usuwa katalogi, które zawierają tylko inne puste katalogi (czego chce również OP). Zauważam, że twoje polecenie zwykle pozostawia użytkownika w katalogu z brakującym i-node, nawet jeśli osiągną to, czego chcą, co może być dla nich mylące. Może nie rozumiem.
Dr. Osoba II
23

find . -type d -empty

znajduje i wyświetla puste katalogi i podkatalogi w bieżącym drzewie. Np. Wynikowa lista pustych katalogów i podkatalogów:

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

Na katalogach nie jest wykonywana żadna operacja. Są po prostu wymienione. To działa dla mnie.

user7194913
źródło
16

Po prostu znajdź puste reżery

Aby znaleźć puste katalogi (jak określono w tytule pytania), odpowiedź mosg jest poprawna:

find -type d -empty

Ale -emptymoże nie być dostępny w bardzo starych findwersjach (tak jest na przykład w przypadku HP-UX ). W takim przypadku zapoznaj się z technikami opisanymi w poniższej sekcji Czy katalog jest pusty? .

Usuń puste książki

Jest to trochę skomplikowane: załóżmy, że katalog MyDirzawiera puste katalogi. Po usunięciu tych pustych katalogów MyDirstanie się pustym katalogiem i również powinien zostać usunięty. Dlatego używam polecenia rmdirz opcją --parents(lub -p), która usuwa również katalogi nadrzędne, jeśli to możliwe:

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

W starszej findwersji instrukcja +nie jest jeszcze obsługiwana, dlatego możesz użyć ;zamiast niej:

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

Czy katalog jest pusty?

Większość z tych odpowiedzi wyjaśnia, jak sprawdzić, czy katalog jest pusty. Dlatego przedstawiam tutaj trzy różne techniki, które znam:

  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
    

    odmiana:

    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
    

    Wyjaśnienie:

    • find -prunejest podobny do find -maxdepth 0użycia mniejszej liczby znaków
    • find -type d drukuje tylko katalogi
    • find -empty wypisuje puste katalogi i pliki

      > 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} ))

    Ta sztuczka jest w 100%, bashale wywołuje (spawnuje) podpowłokę. Pomysł pochodzi od Bruno De Fraine i został ulepszony przez teambob komentarzem . Radzę to, jeśli używasz i jeśli twój skrypt nie musi być przenośny.

    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
    

    Uwaga: nie ma różnicy między pustym katalogiem a katalogiem nieistniejącym (nawet jeśli podana ścieżka jest plikiem).

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

    Ta sztuczka została zainspirowana artykułem nixCraft opublikowanym w 2007 roku. Andrew Taylor odpowiedział w 2008 roku, a gr8can8dian w 2011 roku.

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

    lub jednowierszowa wersja bashism:

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

    Uwaga: ls zwraca, $?=2gdy katalog nie istnieje. Ale nie ma różnicy między plikiem a pustym katalogiem.

olibre
źródło
rmdir -vpbardzo mi pomogło, ponieważ musiałem nie tylko usunąć wszystkie puste katalogi w katalogu głównym, ale sprawdzić puste katalogi i katalogi nadrzędne po usunięciu pliku. W mojej sytuacji puste katalogi są w porządku, o ile nie ma ich w drzewie, z którego obecnie usuwam plik. Dzięki!
Ethan Hohensee,
2

Wydaje się, że ta rekurencyjna funkcja załatwia sprawę:

# 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
}

Biorąc pod uwagę przykładową strukturę katalogów:

    .
    | - dir1 /
    | - dir2 /
    | `- dirB /
    | - dir3 /
    | `- dirC /
    | `- plik5
    | - dir4 /
    | | - reż /
    | `- plik4
    `- dir5 /
        `- reż /
            `- dir_V /

Wynikiem działania tej funkcji byłby:

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

który chybia /dir4/dirD. Jeśli przeniesiesz wywołanie rekurencyjne findempty "$dir"po znaku fi, funkcja uwzględni ten katalog w swoich wynikach.

Wstrzymano do odwołania.
źródło
2

A co powiesz rmdir *? To polecenie zakończy się niepowodzeniem w przypadku niepustych katalogów.

evandrix
źródło
Coś, co robiłem czasami, dla ogólnego sprzątania. Robiono również rzeczy takie jak rmdir */*/* */* * chociaż nie obsługuje plików z kropkami, ale w sytuacjach ręcznych (czyszczenie plików danych) generalnie nie spodziewasz się plików z kropkami. Metody rekurencyjne służą jednak do bardziej zautomatyzowanego ogólnego czyszczenia, szczególnie w bardzo dużych strukturach katalogów.
antoni
W jednym przypadku było to bardziej skomplikowane, ponieważ musiałem usunąć puste katalogi, w których „puste” obejmowały katalogi, które mogły zawierać pojedynczy plik „readme”. Coś innego w katalogu i nie było to „puste”. W tym przykładzie struktura katalogów obejmowała dziesiątki tysięcy podkatalogów.
anthony
1

Poniższe polecenie zwraca 1, jeśli katalog jest pusty (lub nie istnieje), a 0 w przeciwnym razie (więc można odwrócić kod powrotu !w skrypcie powłoki):

find $dir -type d -prune -empty -exec false {} +
Mateusz Piotrowski
źródło
0

Stworzyłem prostą strukturę w następujący sposób:

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

test/test3/fileZawiera jakiś tekst śmieci.

Wystawienie find test -emptyzwraca „ test/test2/test2.2” jako jedyny pusty katalog.

James Sumners
źródło
W rzeczy samej. Ale pomyślałem, że mógłby przeczytać stronę podręcznika znajdowania, aby przejść dalej. Skrypt dostosowujący głębokość na podstawie wyników działałby dobrze.
James Sumners
To była najbardziej przydatna wersja do mojego użytku, dzięki
Andreas,
0

prostym podejściem byłoby:

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

również,

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