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

126

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 eu preciso ser executado várias vezes para remover diretórios contendo apenas diretórios vazios. Além disso, é bastante lento, especialmente sob cygwin.

    
por maaartinus 01.03.2011 / 22:48

5 respostas

177

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

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

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

    
por 02.01.2014 / 15:34
50

Listar 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 lentidão significativa, já que você precisaria invocar um shell intermediário.)

Você pode evitar a execução de rmdir em diretórios não vazios, passando o predicado -empty para localizar. O GNU encontra testes no diretório quando está prestes a executar o comando, então os diretórios que acabaram de ser esvaziados serão selecionados.

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

Outra maneira de acelerar seria agrupar as invocações rmdir . Ambos são notavelmente mais rápidos que o original, especialmente no Cygwin. Eu 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ê tem. Você não pode combinar -empty com métodos para agrupar invocações, porque os diretórios que contêm apenas diretórios vazios não estão vazios no momento em que find olha para eles.

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

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

Como alternativa, use zsh. O qualificador de glob F corresponde a diretórios não vazios, por isso /^F corresponde a vazio diretórios. 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.)

    
por 01.03.2011 / 23:08
5

Se você apenas marcar um -p no seu rmdir , isso funcionará em um passo. Não será bonito nem ótimo, 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 test para encontrar, por isso não se incomoda com diretórios não vazios.

    
por 01.03.2011 / 23:06
1

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

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

As outras respostas dadas aqui infelizmente dependem de melhorias específicas do fornecedor que não existem em todos os sistemas.

    
por 06.11.2015 / 13:48
-1
O comando

rm -r */ funcionou facilmente para mim. rm deve exigir que -f remova obrigatoriamente os diretórios com arquivos. rm -r só deve remover diretórios vazios. Estou aberto a porque isso pode estar errado. Isso também deve deixar os arquivos, pois */ só consulta as pastas.

    
por 22.06.2018 / 16:36