Elimina recursivamente directorios vacíos en Windows

94

Tengo un directorio en mi máquina con Windows 7 que tiene cientos, si no miles, de subdirectorios. Algunos de ellos tienen archivos, otros no. Quiero eliminar todos los directorios vacíos.

Mirando el comando del y rmdir DOS, no parece que puedas hacer esto de forma recursiva sin eliminar todos los archivos. ¿Hay alguna manera de hacer esto desde la línea de comando?

Mohlsen
fuente
Me sorprende que no haya una respuesta simple a esta pregunta.
billpg
@billpg: sencilla, ya que podría obtener: xcopy FROMDIR TODIR /s. Vea esta respuesta SO: stackoverflow.com/a/14742810
eckes el
1
XCOPY elimina directorios?
billpg
1
Se puede hacer fácilmente usando ROBOCOPY. Vea mi respuesta a continuación para más detalles.
Varun Sharma

Respuestas:

116

Puede usar la utilidad Eliminar directorios vacíos .

Alternativamente, puede usar este archivo por lotes de una línea (de DownloadSquad ):

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

(si se usa dentro de un archivo por lotes, reemplácelo %dcon %%d)

Esto funciona porque rdno eliminará un directorio que contenga archivos.

monstruo
fuente
66
PD: le sugiero que pruebe primero la herramienta basada en GUI, antes de probar cualquier comando de línea de comandos que pueda eliminar todos los archivos.
caliban
1
Asegúrate de que esté realmente vacío. Un desktop.ini oculto todavía se considera un archivo. lo mismo que un thumbs.db. Si desea verificar si esto funciona, cree un directorio de prueba con directorios dentro que estén vacíos y poblados. Funciona, lo he verificado.
caliban
1
Sí. Funciona. Mi error.
EBGreen
8
para / f% d en ( 'dir / s / b') no rmdir "% d" deben trabajar como rmdir no puede eliminar una carpeta no vacía
seanyboy
1
Consulte stackoverflow.com/a/34025977/694360 para averiguar cómo agregar esta funcionalidad al menú contextual.
mmj
49

También puedes usar ROBOCOPY. Es muy simple y también se puede usar para eliminar carpetas vacías dentro de una jerarquía grande.

ROBOCOPY folder1 folder1 /S /MOVE

Aquí se encuentran tanto el origen como el destino folder1, ya que solo necesita eliminar carpetas vacías, en lugar de mover otros archivos a una carpeta diferente. /SLa opción es omitir la copia (mover, en el caso anterior) carpetas vacías. También es más rápido ya que los archivos se mueven dentro de la misma unidad.

Varun Sharma
fuente
1
Magia. Entonces, esto mueve todas las carpetas no vacías a la misma ubicación en la que ya se encontraban (¿entonces no pasa nada?) Y omite las carpetas vacías? Pero entonces: ¿por qué omitirlos daría como resultado la eliminación? ¿Y esto no movería carpetas anidadas folder1? Miedo, a menos que se haya probado bien.
Arjan
3
@Arjan ¡Lo he probado y funciona perfectamente! Para comprender su funcionamiento, es como mover todos los archivos a una ubicación diferente, excepto las carpetas vacías, y luego eliminar las carpetas vacías que quedan. /MOVEprimero copia los archivos y luego elimina el archivo fuente después de copiar. Entonces, como /Sse usa, copia las carpetas no vacías al destino (la misma carpeta en el caso anterior). Luego, elimina las carpetas vacías (como si pensara que las carpetas vacías ya se han copiado). No, no mueve las carpetas anidadas folder1, ya que ROBOCOPY mueve las carpetas de forma recursiva.
Varun Sharma
3
¡incluso funciona con rutas UNC (al menos en win7)! Brillante!
Arioch 'The
2
Esta es una solución muy elegante sin necesidad de ningún software de terceros. ¡Gracias!
Marcus Mangelsdorf
1
Esto simplemente hizo su magia y funcionó perfectamente. ¡Gracias!
CharleyDC5
15

Como Cygwin viene con GNU find, puedes hacer esto:

find . -type d -empty -delete

O para evitar el ruido cuando una carpeta ya no existe:

find . -type d -empty -execdir rmdir {} +
Garfio
fuente
Esto ahora también se puede hacer con Windows 10 Bash.
Marzo Ho
Para mi instalación de Windows 10, esto ( find . -type d -empty -delete) falla desde el símbolo del sistema con el siguiente error:FIND: Parameter format not correct
ImpressTheNet Web Developer
7

La utilidad gratuita EmptyFolderNuker hace esto bien, desde una carpeta base de su elección. También elimina aquellos directorios que solo contienen subdirectorios vacíos.

Rob Kam
fuente
1
El archivo por lotes de una sola línea no funcionó para mí (aparece el error "%% d fue inesperado en este momento"), y el programa Eliminar directorios vacíos no se instalará (dice en la página vinculada que no es compatible con Windows 7 de todos modos). Este programa funcionó a las mil maravillas.
Phoenix
1
Como user36580 escribió a continuación, "es probable que esté ejecutando directamente desde la línea de comandos. En ese caso, cambie el doble %% a un solo%"
Lachlan McD.
1
Me gusta esto sobre la versión de línea de comandos pura, ya que le permite obtener una vista previa de las cosas que se eliminan. Siempre puede llamarlo desde la línea de comandos usando "%~dp0\EmptyFolderNuker.exe" %cd%.
Jeroen Wiert Pluimers
1
@ rob-kam La URL de "EmptyFolderNuker" ya no está disponible.
PeterCo
@PeterCo Gracias, arreglado ahora.
Rob Kam
0

Si tiene instalado Cygwin , puede hacer esto:

find -type d -exec rmdir {} \;
Anthony Giorgio
fuente
44
No necesariamente. Es posible que eso no elimine directorios con solo subdirectorios vacíos. Puede que tenga que revertirlo. find -type d -print0 | tac | xargs -0 rmdir
Ryan Thompson
Nunca supe sobre "tac" antes. Eso es realmente ingenioso!
Anthony Giorgio
1
O usar . La opción le dice que haga algo como invertir el orden de la salida: primero va a los niveles de directorio más profundos y luego vuelve a subir. find (starting-directory) -depth -type d ...-depthfind
G-Man
0

Si está trabajando en emacs (haciendo que esta plataforma sea independiente), lo siguiente 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
fuente
... Por favor, dime que no tendrías que escribir todo esto para lograr esto en emacs.
Hashim
1
@Hashim La idea es que lo tengas definido en tu init y luego vinculado a una clave. Técnicamente, podría hacerlo Dsi quisiera, pero como no tengo una necesidad común de esto, todo lo que tengo que escribir es M-x *ded RETbam – done. (Si realmente tuviera que escribir esto cada vez, tiene toda la razón de que sería absurdo, afortunadamente ese no es el caso)
Sean Allred
Bastante justo, eso suena más plausible.
Hashim
¿ M-x *ded RETTiene algún significado o es al azar? Si es esto último, ¿cómo realiza un seguimiento de todos los accesos directos que ha asignado emacs? ¿Es suficiente la memorización o tienes que buscarlos?
Hashim
1
@Hashim *dedes una abreviatura para el nombre completo de la función *-delete-empty-directories. Muchos motores de terminación (como la hiedra, la que uso) entienden este tipo de coincidencia difusa. En cuanto a mantenerlos memorizados ... Simplemente no tengo que hacerlo. Todas las funciones que he definido comienzan por *lo que puedo encontrarlas fácilmente si no están vinculadas a una tecla. De lo contrario, el propio emacs me dirá si había una forma más rápida de llamar a la función. Si todo lo demás falla, siempre hay apropos.
Sean Allred
0

Combinando las publicaciones de Gareth y G-Man:

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

Editar: Pero eso dio un error de seguridad debido a 'C' en mi PATH var ... así que en su lugar:

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

No uso xargs porque parece tener un límite de línea de entrada (de aproximadamente 1024 líneas, creo), mientras que

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

solo continúa mientras tenga entrada. Omita el indicador detallado '-v' si no desea ver los resultados o desea que se ejecute más rápido.

skeetastax
fuente
0

Hmmm ... tal vez una solución aún más simple:

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

Comience esto desde la carpeta que desea que se eliminen las carpetas vacías.

/ d: funcionará en carpetas, no en archivos / r: repetirá subdirecciones

Daniel Mošmondor
fuente