Excluir recursivamente diretórios vazios no Windows

94

Eu tenho um diretório na minha máquina Windows 7 que possui centenas, se não milhares, de subdiretórios. Alguns deles têm arquivos, outros não. Eu quero excluir todos os diretórios vazios.

Observando o comando del e rmdir DOS, não parece que você pode fazer isso recursivamente sem excluir todos os arquivos. Existe uma maneira de fazer isso na linha de comando?

Mohlsen
fonte
Estou surpreso que não haja uma resposta simples para essa pergunta.
billpg
@billpg: simples como poderia obter: xcopy FROMDIR TODIR /s. Veja esta resposta do SO: stackoverflow.com/a/14742810
eckes
1
XCOPY exclui diretórios?
billpg
1
Isso pode ser feito facilmente usando o ROBOCOPY. Veja minha resposta abaixo para obter detalhes.
Varun Sharma

Respostas:

116

Você pode usar o utilitário Remover Diretórios Vazios .

Como alternativa, você pode usar este arquivo em lotes de uma linha (do DownloadSquad ):

for /f "delims=" %d in ('dir /s /b /ad ^| sort /r') do rd "%d"

(se usado dentro de um arquivo em lotes, substitua %dpor %%d)

Isso funciona porque rdnão removerá um diretório que contém arquivos.

caliban
fonte
6
PS: sugiro que você tente primeiro a ferramenta baseada em GUI, antes de tentar qualquer comando de linha de comando que possa potencialmente excluir todos os arquivos.
caliban
1
Verifique se ele está realmente vazio. Um desktop.ini oculto ainda é considerado um arquivo. o mesmo que um thumbs.db. Se você deseja verificar se isso funciona, crie um diretório de teste com diretórios dentro que estejam vazios e preenchidos. Funciona, eu verifiquei.
caliban
1
Sim. Funciona. Meu erro.
EBGreen
8
para / f% d em ( 'dir / s / b') que rmdir "% d" deve funcionar como rmdir não pode remover uma pasta não-vazia
seanyboy
1
Veja stackoverflow.com/a/34025977/694360 para descobrir como adicionar essa funcionalidade ao menu de contexto.
MMJ
49

Você também pode usar o ROBOCOPY. É muito simples e também pode ser usado para excluir pastas vazias dentro de uma grande hierarquia.

ROBOCOPY folder1 folder1 /S /MOVE

Aqui, tanto a origem quanto o destino são folder1, pois você só precisa excluir pastas vazias, em vez de mover outros arquivos para uma pasta diferente. /SA opção é pular a cópia (movendo, no caso acima) de pastas vazias. Também é mais rápido à medida que os arquivos são movidos dentro da mesma unidade.

Varun Sharma
fonte
1
Magia. Portanto, isso move todas as pastas não vazias para o mesmo local em que elas já estavam (o que não acontece?) E ignora as pastas vazias? Mas então: por que ignorá-los resultaria em exclusão? E isso não moveria pastas aninhadas folder1? Assustador, a menos que testado bem.
Arjan
3
@ Arjan Eu testei e funciona perfeitamente! Para entender como funciona, é como mover todos os arquivos para um local diferente, exceto pastas vazias e excluir as pastas vazias deixadas para trás. /MOVEcopia os arquivos primeiro e exclui o arquivo de origem após a cópia. Portanto, conforme /Sé usado, ele copia as pastas não vazias para o destino (mesma pasta no caso acima). Em seguida, ele exclui as pastas vazias (como pensar que as pastas vazias já foram copiadas). Não, ele não move pastas aninhadas folder1, pois o ROBOCOPY move as pastas recursivamente.
Varun Sharma
3
até funciona com caminhos UNC (pelo menos no win7)! Brilhante!
Arioch 'The
2
Esta é uma solução muito elegante, sem a necessidade de nenhum software de terceiros. Obrigado!
Marcus Mangelsdorf
1
Isso fez sua mágica e funcionou perfeitamente. Obrigado!
CharleyDC5
15

Como o Cygwin vem com o GNU find, você pode fazer o seguinte:

find . -type d -empty -delete

Ou para evitar o barulho quando uma pasta não existir mais:

find . -type d -empty -execdir rmdir {} +
Gaff
fonte
Agora, isso também pode ser feito usando o Windows 10 Bash.
March Ho
Para minha instalação do Windows 10, isso ( find . -type d -empty -delete) falha no prompt de comando com o seguinte erro:FIND: Parameter format not correct
ImpressTheNet Web Developer
7

O utilitário gratuito EmptyFolderNuker faz isso muito bem, a partir de uma pasta base de sua escolha. Ele também remove os diretórios que contêm apenas subdiretórios vazios.

Rob Kam
fonte
1
O arquivo em lotes de uma linha não funcionou para mim (recebo o erro "%% d foi inesperado no momento.") E o programa Remover diretórios vazios não será instalado (na página vinculada, diz que não está). de qualquer maneira compatível com o Windows 7). Este programa funcionou como um encanto.
Phoenix
1
Como o user36580 escreveu abaixo, "é provável que você esteja executando diretamente da linha de comando. Nesse caso, altere o %% duplo para um único%"
Lachlan McD.
1
Gosto disso na versão pura da linha de comando, pois permite visualizar as coisas que são excluídas. Você sempre pode chamá-lo na linha de comando usando "%~dp0\EmptyFolderNuker.exe" %cd%.
Jeroen Wiert Pluimers
1
@ rob-kam O URL para "EmptyFolderNuker" não está mais disponível.
PeterCo
@ PeterCo Obrigado, corrigido agora.
Rob Kam
0

Se você tiver o Cygwin instalado, poderá fazer o seguinte:

find -type d -exec rmdir {} \;
Anthony Giorgio
fonte
4
Não necessariamente. Isso pode não excluir diretórios com apenas subdiretórios vazios. Você pode ter que reverter isso. find -type d -print0 | tac | xargs -0 rmdir
Ryan Thompson
Eu nunca soube de "tac" antes. Isso é realmente bacana!
Anthony Giorgio
1
Ou use . A opção diz para fazer algo como reverter a ordem da saída - ela vai primeiro aos níveis mais profundos do diretório e depois volta ao trabalho. find (starting-directory) -depth -type d ...-depthfind
G-Man
0

Se você estiver trabalhando no emacs (tornando esta plataforma independente), o seguinte funciona:

(defun *-delete-empty-directories (root-directory)
  "Recursively delete empty directories in ROOT-DIRECTORY.

When called from dired, `dired-current-directory' is used for
ROOT-DIRECTORY."

  ;; Interface
  (interactive (list (if (eq major-mode 'dired-mode)
                         (expand-file-name (dired-current-directory))
                       (read-from-minibuffer "Root directory: "))))
  (when (or (null root-directory) (string= "" root-directory))
    (user-error "No root directory provided"))
  (when (called-interactively-p 'interactive)
    (unless (yes-or-no-p (format "Delete all non-empty directories in `%s'? "
                                 root-directory))
      (user-error "Directory `%s' has been left untouched" root-directory)))

  ;; Implementation
  (require 'f)
  (let ((entries (f-directories root-directory)))
    (while entries
      (let ((curdir (car entries)))
        (when (f-directories curdir)
          (*-delete-empty-directories curdir))
        (unless (f-entries curdir)
          (delete-directory curdir)
          (message "Directory deleted: `%s'" curdir))
        (setq entries (cdr entries)))))
Sean Allred
fonte
... Por favor, diga-me que você não precisaria digitar tudo isso para conseguir isso no emacs.
Hashim
1
@Hashim A idéia é que você o tenha definido no seu init e então vinculado a uma chave. Tecnicamente, eu poderia ligá-lo Dse quisesse, mas como não tenho uma necessidade comum disso, tudo o que tenho que digitar é M-x *ded RETe pronto. (Se eu realmente tinha que digitar isso toda vez, você está absolutamente certo de que seria absurdo - felizmente isso não é o caso.)
Sean Allred
Justo, isso parece mais plausível.
Hashim 01/01
Tem M-x *ded RETalgum significado ou é aleatório? Nesse último caso, como você controla todos os atalhos atribuídos emacs? A memorização é suficiente ou você precisa procurá-las?
Hashim 01/01
1
@Hashim *dedé uma abreviação para o nome completo da função *-delete-empty-directories. Muitos mecanismos de conclusão (como o ivy, o que eu uso) entendem esse tipo de correspondência difusa. Quanto a mantê-los memorizados ... eu simplesmente não preciso. As funções que defini são iniciadas *para que eu possa encontrá-las facilmente se não estiverem vinculadas a uma tecla. Caso contrário, o emacs em si me dirá se houve uma maneira mais rápida de chamar a função. Se tudo mais falhar, sempre haverá apropos.
Sean Allred
0

Combinando as postagens de Gareth e G-Man:

find . -depth -type d -empty -execdir rmdir {} +

Edit: Mas isso deu um erro de segurança por causa de 'C' na minha PATH var ... então, em vez disso:

$find . -depth -type d -empty | while read dir; do (rmdir -v $dir); done

Eu não uso xargs porque parece ter um limite de linha de entrada (de cerca de 1024 linhas, eu acho?), Enquanto

 while read x; do (command $x); done

apenas continua enquanto houver entrada. Deixe de fora o sinalizador detalhado '-v' se você não deseja ver os resultados e / ou deseja que ele seja executado mais rapidamente.

skeetastax
fonte
0

Hmmm ... talvez solução ainda mais simples:

for /d /r %d in (*.*) do rd "%d"

Comece isso na pasta em que deseja excluir as pastas vazias.

/ d - funcionará em pastas, não em arquivos / r - recursará subdiretórios

Daniel Mošmondor
fonte