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

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

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ć :-)


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

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.


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.


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.


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.


2

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


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 {} +

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.



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"

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.