Usuń puste drzewa katalogów (usuwając możliwie jak najwięcej katalogów, ale bez plików)

13

Załóżmy, że mam takie drzewo katalogów:

ROOTDIR
    └--SUBDIR1
        └----SUBDIR2
            └----SUBDIR3

Szukam polecenia takiego, że kiedy wprowadzę:

$ [unknown command] ROOTDIR

Całe drzewo katalogów można usunąć, jeśli nie ma pliku, ale tylko katalogi wewnątrz całego drzewa . Powiedzmy jednak, że w pliku SUBDIR1 znajduje się plik hello.pdf:

ROOTDIR
    └--SUBDIR1
        └--hello.pdf
        └----SUBDIR2
            └----SUBDIR3

Następnie polecenie musi usunąć tylko SUBDIR2 i poniżej.

gsklee
źródło
Wydaje się, że jest to kopia Jak usunąć wszystkie puste katalogi w poddrzewie?
David Cary

Odpowiedzi:

11

Alexis jest blisko. Co musisz zrobić, to:

find . -type d -depth -empty -exec rmdir "{}" \;

Spowoduje to najpierw drążenie w dół drzewa katalogów, aż znajdzie pierwszy pusty katalog, a następnie usunięcie go. W ten sposób opróżnianie katalogu nadrzędnego, który zostanie następnie usunięty itp. Spowoduje to pożądany efekt (robię to prawdopodobnie 10 razy w tygodniu, więc jestem pewien, że ma rację). :-)

Steve Juranich
źródło
Dlaczego -depthopcja jest konieczna? find . -type d -empty -exec rmdir "{}" \;powinien również działać .... prawda?
Abhishek A
4
Zastanów się, czy masz drzewo (tylko katalogi) foo/bar/baz. O ile nie użyjesz -depth, spróbuje foonajpierw usunąć , nie powiedzie się, a skończysz foo/barpo uruchomieniu.
l0b0,
1
Być może alternatywą jest użycie +zamiast, ;aby partii usunąć katalogi. Ponieważ robisz to w pierwszej kolejności, dzieci będą nadal usuwane przed rodzicami (być może zależy to od twojej wersji rmdir / bash i zależą od rmdir, który nie usuwa niepustych katalogów). Działa to dla mnie w bash na cygwin:mkdir -p a/b/c/d ; find a -depth -type d -exec rmdir {} +
idbrii
4
Ludzie, idźcie do bardziej zwięzłej odpowiedzi go2null poniżej! Nie mogę zrozumieć, dlaczego SE nadaje pierwszeństwo zaakceptowanym odpowiedziom zamiast odpowiedzi z większością głosów poparcia w wyświetlaniu odpowiedzi poniżej pytania. OP akceptuje najlepszą dostępną odpowiedź w swoim momencie wyboru, ale później mogą przyjść znacznie lepsze odpowiedzi, które społeczność komentuje, prawda? (Oczywiście, to jest coś dla meta ...)
jamadagni
to nie działa dla mnie. usuwa tylko najgłębszy liść (w tym przypadku SUBDIR3)
Joey Baruch,
24
find ROOTDIR -type d -empty -delete

taki sam jak

find ROOTDIR -type d -depth -empty -exec rmdir "{}" \;

ale używa wbudowanej akcji „-delete”.

Zauważ, że „-delete” oznacza „-depth”.

go2null
źródło
Wyrazy uznania za najbardziej zwięzłą odpowiedź za pomocą wbudowanego usuwania funkcji find! Dodaję to do moich lokalnych skryptów narzędzi!
jamadagni
3

Spróbowałbym tego:

find ROOTDIR -type d -depth -exec rmdir {} \;
Alexis
źródło
1

Oto niektóre wymagania, zanim będziemy mogli to zrobić bezpiecznie:

  1. najpierw usuń podkatalogi, a następnie katalogi wyższego poziomu, tzn. musimy posortować listę katalogów lub użyć flagi rmdir --parents
  2. uruchamiaj ROOTDIR zawsze z / lub ./, aby uniknąć niespodzianek z plikami zaczynającymi się od -
  3. użyj zakończonej NUL listy katalogów do pracy z nazwami katalogów ze spacjami

Oto jak zrobiłbym to w powłoce:

find ./ROOTDIR -type d | sort -r | tr '\n' '\000' | xargs -0 rmdir --ignore-fail-on-non-empty

Jeśli nie przeszkadzają ci jakieś zbędne błędy, możesz po prostu wymusić usunięcie wszystkich katalogów z rodzicami i nie musisz przeprowadzać żadnego sortowania (nie możesz sortować NUL zakończonych ciągów, co dodaje konieczność tr)

find ./ROOTDIR -type d -print0 | xargs -0 rmdir --ignore-fail-on-non-empty --parents
Puma
źródło
Wyrazy uznania za szczegółowe wyjaśnienie Twojej odpowiedzi. Prawdopodobnie zastosowałbym to samo podejście, dopóki nie dowiedziałem się o -empty -deleteopcjach odpowiedzi findw @ go2null.
Davor Cubranic
0
rmdir $(find ROOTDIR -type d | sort -r)
Lanzz
źródło
5
To nie zadziała, jeśli którakolwiek z nazw katalogów zawiera białe znaki lub znaki globowania. Generalnie złym pomysłem jest stosowanie podstawiania poleceń na liście nazw plików. Jest to szczególnie zły pomysł z findponieważ findma sposób, aby wykonać obróbkę czysto: find … -exec.
Gilles 'SO - przestań być zły'
Dzięki Gillesowi za zwrócenie na to uwagi. @lanzz, zwykle publikowanie tylko polecenia bez wyjaśnienia, co robi (w tym przypadku pułapki) nie wystarczy. Dodaj do swojej odpowiedzi.
n0pe
0

Zrobiłbym to:

find ROOTDIR -type d | xargs -0 -I {} rmdir {}
chemila
źródło