Bir alt ağaçtaki tüm boş dizinler nasıl kaldırılır?


151

Bir alt ağaçtaki tüm boş dizinleri nasıl kaldırabilirim? Gibi bir şey kullandım

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

ancak yalnızca boş dizinler içeren dizinleri kaldırmak için birkaç kez çalıştırmam gerekiyor. Dahası, özellikle cygwin altında oldukça yavaştır.


Ayrıca bir emacs çözümü için emacs.stackexchange.com/q/12190/2264 adresine bakın .
Sean Allred

Yanıtlar:


222

GNU findseçeneklerini ve tahminlerini birleştirerek bu komut işi yapmalıdır:

find . -type d -empty -delete
  • -type d dizinlerle sınırlıdır
  • -empty boş olanlarla kısıtlar
  • -delete her dizini siler

Ağaç -depth, ima edildiği şekilde belirtmeye gerek kalmadan yapraklardan yürür -delete.


2
-deletezaten ima ediyor, -depthbu yüzden bunu manuel olarak belirtmenize gerek yok.
jamadagni

1
Teşekkürler, farkında değildim. Cevap güncellendi.
Christophe Drevet-Droguet

11
Ben eklersiniz -mindepth 1boş olurdu, başlangıç dizini kendisini silmesini önlemek için, burada.
Greg Dubicki

2
Harika, ama eski SunOS ev sahiplerim üzerinde çalışmıyor ...
dokaspar

2
!kabuğu için özel bir anlamı vardır. Ondan kaçman gerek. Gibi bir şey: \! -name 'Completed'hemen önce -deleteçalışması gerekir. Ya da sadece bu dizine bir marker dosyası koymak.
Christophe Drevet-Droguet

53

Önce derinlemesine yuvalanmış dizinleri listeleyin.

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

( Yönlendirmenin yalnızca findkomut için değil, bir bütün olarak geçerli olduğunu unutmayın rmdir. Yalnızca yeniden yönlendirmek, rmdirbir ara kabuk çağırmanız gerekeceğinden önemli bir yavaşlamaya neden olur.)

Tahmini bulmak rmdiriçin -emptyyüklemeyi geçerek boş olmayan dizinlerde yayın yapmaktan kaçınabilirsiniz . GNU find, komutu çalıştırmak üzere olduğunda dizini test eder, bu nedenle yeni boşaltılmış dizinler alınacaktır.

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

Hızlandırmanın başka bir yolu da rmdiristilaları gruplandırmak olacaktır . Her ikisinin de, özellikle Cygwin altında, orijinalinden belirgin şekilde daha hızlı olması muhtemeldir. Bu ikisi arasında fazla fark beklemiyorum.

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

Hangi yöntemin daha hızlı olduğu, kaç tane boş olmayan dizininiz olduğuna bağlıdır. -emptyÇağrıları gruplama yöntemleriyle birleştiremezsiniz , çünkü o zaman yalnızca boş dizinler içeren dizinler zamana göre boş değildir find.

Başka bir yöntem, birden çok geçiş çalıştırmaktır. Bunun daha hızlı olup olmadığı, tüm dizin hiyerarşisinin, findçalıştırmalar arasındaki disk önbelleğinde kalıp kalmayacağı da dahil olmak üzere birçok şeye bağlıdır .

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

Alternatif olarak, zsh kullanın. Glob eleme F yüzden, boş olmayan dizinleri maçları /^Fboş dizinleri eşleşir. Yalnızca boş dizinler içeren dizinler o kadar kolay eşleştirilemez.

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

(Bu rmdir, boş bir komut satırı aldığında sona erer .)


Bu kadar. 90 saniye yerine 0,90 sn sürer.
maaartinus

@maaartinus: Merak ediyorum: onsuz deneyebileceğiniz benzer bir veri setiniz var -pmı? Bir fark yaratacağını düşünmezdim.
Gilles

3
@maartinus - diğer küçük optimizasyonlar: ekleme -emptybununla çalışmalı (tam olarak ne kadar kazanacağından emin olmasam da ). Ve çok, çok önemsiz, muhtemelen kaldırmak istemediğiniz için .kullanın -mindepth 1.
mattdm

Çıkarma değildi, ancak işlem neredeyse başından beri sürdü. İşe yaramaz -deptholan argümanı gözden kaçırmıştım rmdir -p. Yorumumu zaten değiştirdim. 90'lı yıl benim orijinal girişimdi; Burada şaşırtıcı hiçbir şey yok.
maaartinus

2
rmdirKomut çağrısını tamamen kaldırabileceğimizi anladım , en azından GNU bulduktan sonra, bu komutla:find . -depth -type d -empty -delete
Christophe Drevet-Droguet

6

Eğer sadece bir çakmak olursa -psizinle ilgili şu rmdirki tek bir geçişte çalışacağız. Güzel ya da optimal olmayacak, ama her şeyi almalı. Bu, rmdir'e, kaldırmakta olduğunuzdan birinin boş olmayan üst dizinlerini kaldırmasını söyler.

Bulmak için -emptysınama ekleyerek biraz tasarruf edebilirsiniz , böylece boş olmayan dizinlerle uğraşmaz.


3

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

bu sorunun en basit ve standart uyumlu cevabı.

Burada verilen diğer cevaplar maalesef, tüm sistemlerde bulunmayan satıcıya özgü geliştirmelere dayanmaktadır.


3
Bu cevap, silinemeyen her dizin için istenenden daha az olabilecek bir hata veriyor.
Willem van Ketwich

0

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

İşte nasıl çalışıyor:

  1. Tüm dizinleri derinlikleriyle birlikte tekrarlı bir şekilde listeleyin
  2. Derinliklerinin azalan düzenine göre sırala
  3. Yalnızca dizin yollarını filtrele
  4. rmdirListede birer birer çalıştırın

0

Bu takma adları sık kullanılan findkomutlar için kullanıyorum, özellikle dupeguru kullanarak disk alanını temizlerken , yinelenenleri silmenin çok fazla boş dizine neden olabileceği durumlarda.

İçerde yorumlar .bashrcbu yüzden çimdikmem gerektiğinde onları daha sonra unutmayacağım.

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

-2

rm -r */komut benim için kolayca çalıştı. Dosyaları dizinlerle zorla kaldırmanız rmgerekir -f. rm -rsadece boş dizinleri çıkarmalı. Bunun neden yanlış olabileceğine açığım. Bu, */yalnızca klasörlere baktığından da dosya bırakmalıdır .


1
rmÖncelikle dosyaları kaldırmak için öncelikle olduğu gibi iyice test etmenizi şiddetle tavsiye ediyorum . İken */sadece dizinleri maçları, ben daha derin seviyelerini, bunu yapıyor hiçbir fikrim yok. Bunun sadece bazı sistemlerde çalıştığını da hayal edebiliyorum.
maaartinus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.