desenv-web-rp.com

Como remover todos os diretórios vazios em uma subárvore?

Como posso remover todos os diretórios vazios em uma subárvore? Eu usei algo como

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

mas preciso executar várias vezes para remover diretórios que contêm apenas diretórios vazios. Além disso, é bastante lento, especialmente no cygwin.

159
maaartinus

Combinando GNU find opções e predicados, este comando deve fazer o trabalho:

find . -type d -empty -delete
  • -type d restringe a diretórios
  • -empty restringe aos vazios
  • -delete remove cada diretório

A árvore é retirada das folhas sem a necessidade de especificar -depth como está implícito por -delete.

237
Christophe Drevet-Droguet

Liste os diretórios profundamente aninhados primeiro.

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

(Observe que o redirecionamento se aplica ao comando find como um todo, não apenas a rmdir. Redirecionar apenas para rmdir causaria uma desaceleração significativa, pois você precisaria chamar Shell intermediário.)

Você pode evitar executar rmdir em diretórios não vazios, passando o -empty predicado a encontrar. GNU find testa o diretório quando está prestes a executar o comando, para que os diretórios que acabaram de ser esvaziados sejam selecionados.

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

Outra maneira de acelerar seria agrupar as invocações rmdir. É provável que ambos sejam visivelmente mais rápidos que o original, especialmente no Cygwin. Não espero muita diferença entre esses dois.

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

Qual método é mais rápido depende de quantos diretórios não vazios você possui. Você não pode combinar -empty com métodos para agrupar chamadas, porque os diretórios que contêm apenas diretórios vazios não ficam vazios até o momento find os examina.

Outro método seria executar várias passagens. Se isso é mais rápido depende de muitas coisas, incluindo se toda a hierarquia de diretórios pode permanecer no cache do disco entre find executadas.

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

Como alternativa, use zsh. O qualificador globalF corresponde a diretórios não vazios, portanto /^F corresponde a diretórios vazios. Diretórios que contêm apenas diretórios vazios não podem ser correspondidos tão facilmente.

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

(Isso termina quando rmdir recebe uma linha de comando vazia.)

53

Se você apenas alinhavar um -p no seu rmdir, isso funcionará de uma só vez. Não será bonito ou ideal, mas deve ter tudo. Isso diz ao rmdir para remover qualquer diretório pai não vazio daquele que você está removendo.

Você pode economizar um pouco adicionando o -empty teste para encontrar, para não incomodar com diretórios não vazios.

6
mattdm

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

é a resposta mais simples e compatível com esta pergunta.

Infelizmente, as outras respostas fornecidas aqui dependem de aprimoramentos específicos do fornecedor que não existem em todos os sistemas.

3
schily

Eu uso esses aliases para comandos find usados ​​com freqüência, especialmente quando eu limpo o espaço em disco usando dupegur, onde a remoção de duplicatas pode resultar em muitos diretórios vazios.

Comentários dentro de .bashrc para não esquecê-los mais tarde, quando precisar ajustá-lo.

# 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

Veja como funciona:

  1. Liste recursivamente todos os diretórios, juntamente com sua profundidade
  2. Classificar por ordem decrescente da profundidade
  3. Filtrar apenas os caminhos do diretório
  4. Execute rmdir na lista, um por um
0
Ashish Ranjan