it-swarm-eu.dev

Jak odstranit všechny prázdné adresáře v podstromu?

Jak mohu odstranit všechny prázdné adresáře v podstromu? Použil jsem něco jako

find . -type d -exec rmdir {} 2>/dev/null \;

ale musím běžet vícekrát, abych odstranil pouze adresáře obsahující prázdné adresáře. Navíc je to docela pomalé, zejména u cygwina.

159
maaartinus

Při kombinaci GNU find možností a predikátů by tento příkaz měl provést tuto úlohu:

find . -type d -empty -delete
  • -type d omezuje na adresáře
  • -empty omezuje se na prázdné
  • -delete odebere každý adresář

Strom je vycházel z listů bez nutnosti specifikovat -depth jak to implikuje -delete.

Seznamy adresářů hluboce vnořených-první.

find . -depth -type d -exec rmdir {} \; 2>/dev/null

(Všimněte si, že přesměrování se vztahuje na příkaz find jako celek, nejen na příkaz rmdir. Přesměrování pouze pro rmdir by způsobilo výrazné zpomalení, protože byste museli vyvolat prostřední Shell.)

Můžete se vyhnout spuštění rmdir na neprázdných adresářích předáním -empty predikát k nalezení. GNU find testuje adresář, když se chystá spustit příkaz, takže budou odebrány právě vyprázdněné adresáře).

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

Dalším způsobem, jak urychlit, by bylo seskupení rmdir vyvolání. Oba pravděpodobně budou znatelně rychlejší než původní, zejména za Cygwina. Neočekávám velký rozdíl mezi těmito dvěma.

find . -depth -type d -print0 | xargs -0 rmdir 2>/dev/null
find . -depth -type d -exec rmdir {} + 2>/dev/null

Která metoda je rychlejší záleží na tom, kolik neprázdných adresářů máte. Nemůžete kombinovat -empty s metodami pro seskupování vyvolání, protože pak adresáře, které obsahují pouze prázdné adresáře, nejsou do doby find prázdné.

Další metodou by bylo spuštění více průchodů. Zda je to rychlejší, záleží na mnoha věcech, včetně toho, zda celá hierarchie adresářů může zůstat v mezipaměti disku mezi spuštěním find.

while [ -n "$(find . -depth -type d -empty -print -exec rmdir {} +)" ]; do :; done

Případně použijte zsh. kvalifikátor globF odpovídá neprázdným adresářům, takže /^F odpovídá prázdným adresářům. Adresáře, které obsahují pouze prázdné adresáře, nelze tak snadno sladit.

while rmdir **/*(/N^F); do :; done

(Toto skončí, když rmdir obdrží prázdný příkazový řádek.)

Pokud si jen připínáš -p na vašem rmdir, bude to fungovat v jednom průchodu. Nebude to hezké nebo optimální, ale mělo by to všechno. To rmdir říká, aby odstranil všechny neprázdné nadřazené adresáře toho, který odstraňujete.

Trochu můžete ušetřit přidáním -empty test najít, takže se neobtěžuje s neprázdné adresáře.

6
mattdm

find . -depth -type d -exec rmdir {} +

je nejjednodušší a standardní odpověď na tuto otázku.

Ostatní zde uvedené odpovědi bohužel závisí na vylepšeních specifických pro dodavatele, která ve všech systémech neexistují.

3
schily

Tyto aliasy používám pro často používané příkazy find, zejména když vyčistím místo na disku pomocí dupegur, kde odstranění duplikátů může vést k mnoha prázdným adresářům.

Komentáře uvnitř .bashrc tak na ně nezapomenu později, když to potřebuji vyladit.

# find empty directories
alias find-empty='find . -type d -empty'

# fine empty/zero sized files
alias find-zero='find . -type f -empty'

# delete all empty directories!
alias find-empty-delete='find-empty -delete'

# delete empty directories when `-delete` option is not available.
# output null character (instead of newline) as separator. used together
# with `xargs -0`, will handle filenames with spaces and special chars.
alias find-empty-delete2='find-empty -print0 | xargs -0 rmdir -p'

# alternative version using `-exec` with `+`, similar to xargs.
# {}: path of current file
# +: {} is replaced with as many pathnames as possible for each invocation.
alias find-empty-delete3='find-empty -exec rmdir -p {} +'

# for removing zero sized files, we can't de-dupe them automatically
# since they are technically all the same, so they are typically left
# beind. this removes them if needed.
alias  find-zero-delete='find-zero -delete'
alias find-zero-delete2='find-zero -print0 | xargs -0 rm'
alias find-zero-delete3='find-zero -exec rm {} +'
0
raychi

find . -type d -printf "%d %p\n" |\ sort -nr |\ Perl -pe 's/^\d+\s//;' |\ while read dir; do \ (rmdir "$dir" > /dev/null 2>&1); \ done

Funguje to takto:

  1. Rekurzivně seznam všech adresářů spolu s jejich hloubkou
  2. Seřadit podle sestupného pořadí jejich hloubky
  3. Filtrujte pouze cesty k adresáři
  4. Spusťte rmdir v seznamu jeden po druhém
0
Ashish Ranjan