Рекурсивно удалить пустые каталоги в Windows

94

У меня на Windows 7 есть каталог, в котором есть сотни, если не тысячи подкаталогов. У некоторых из них есть файлы, у некоторых нет. Я хочу удалить все пустые каталоги.

Глядя на команду del и rmdir DOS, не похоже, что вы можете сделать это рекурсивно, не удаляя все файлы. Есть ли способ сделать это из командной строки?

mohlsen
источник
Я поражен, что нет простого ответа на этот вопрос.
billpg
@billpg: просто , как он мог бы получить: xcopy FROMDIR TODIR /s. Смотрите этот SO ответ: stackoverflow.com/a/14742810
eckes
1
XCOPY удаляет каталоги?
billpg
1
Это можно легко сделать с помощью ROBOCOPY. Смотрите мой ответ ниже для деталей.
Варун Шарма

Ответы:

116

Вы можете использовать утилиту удаления пустых каталогов .

В качестве альтернативы вы можете использовать этот однострочный пакетный файл (из DownloadSquad ):

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

(если используется внутри командного файла, заменить %dна %%d)

Это работает, потому rdчто не удалит каталог, содержащий файлы.

Калибан
источник
6
PS Я предлагаю вам сначала попробовать инструмент на основе графического интерфейса, прежде чем пытаться выполнять какие-либо команды командной строки, которые потенциально могут удалить все файлы.
калибан
1
Убедитесь, что он действительно пустой. Скрытый desktop.ini все еще считается файлом. такой же как thumbs.db. Если вы хотите проверить, работает ли это, создайте тестовый каталог с пустыми и заполненными каталогами внутри. Это работает, я проверил.
откалиброван
1
Ага. Оно работает. Виноват.
EBGreen
8
для / f% d в ('dir / s / b') do rmdir "% d" должен работать, так как rmdir не может удалить непустую папку
seanyboy
1
Посмотрите на stackoverflow.com/a/34025977/694360, чтобы узнать, как добавить эту функцию в контекстное меню.
ММД
49

Вы также можете использовать ROBOCOPY. Это очень просто и может также использоваться для удаления пустых папок внутри большой иерархии.

ROBOCOPY folder1 folder1 /S /MOVE

Здесь и источник и место назначения folder1, так как вам нужно только удалить пустые папки, а не перемещать другие файлы в другую папку. /Sвозможность пропустить копирование (перемещение, в указанном выше случае) пустых папок. Это также быстрее, поскольку файлы перемещаются внутри одного диска.

Варун Шарма
источник
1
Магия. Таким образом, это перемещает все непустые папки в то же место, в котором они уже находились (так ничего не происходит?), И пропускает пустые папки? Но тогда: почему пропуск их приводит к удалению? И не будет ли это перемещать вложенные папки в folder1? Страшно, если не проверено хорошо.
Арджан
3
@Arjan Я проверил это, и он отлично работает! Чтобы понять, как это работает, все равно, что переместить все файлы в другое место, кроме пустых папок, а затем удалить оставленные пустые папки. /MOVEсначала копирует файлы, а затем удаляет исходный файл после копирования. Таким образом, при /Sиспользовании он копирует непустые папки в место назначения (та же папка в приведенном выше случае). Затем он удаляет пустые папки (например, думает, что пустые папки уже скопированы). Нет, он не перемещает вложенные папки folder1, так как ROBOCOPY рекурсивно перемещает папки.
Варун Шарма
3
это даже работает с путями UNC (по крайней мере на win7)! Блестящий!
Ариох
2
Это очень элегантное решение без какого-либо стороннего программного обеспечения. Спасибо!
Маркус Мангельсдорф
1
Это только сделало свое волшебство и работало отлично. Спасибо!
CharleyDC5
15

Так как Cygwin поставляется с GNU find, вы можете сделать это:

find . -type d -empty -delete

Или чтобы избежать шума, когда папка больше не существует:

find . -type d -empty -execdir rmdir {} +
багор
источник
Теперь это также можно сделать с помощью Windows 10 Bash.
Март Хо
Для моей установки Windows 10 это ( find . -type d -empty -delete) не выполняется из командной строки со следующей ошибкой:FIND: Parameter format not correct
ImpressTheNet Web Developer
7

Бесплатная утилита EmptyFolderNuker делает это нормально из базовой папки на ваш выбор. Также удаляются те каталоги, которые содержат только пустые подкаталоги.

Роб Кам
источник
1
У меня не работал однострочный пакетный файл (я получаю сообщение об ошибке "%% d было неожиданно в это время."), И программа удаления пустых каталогов не будет установлена ​​(на связанной странице указано, что это не так в любом случае совместим с Windows 7). Эта программа работала как шарм.
Феникс
1
Как пишет user36580 ниже, «скорее всего, вы работаете прямо из командной строки. В этом случае измените двойной%% на один%»
Лахлан МакД.
1
Мне это нравится по сравнению с чистой версией командной строки, так как она позволяет вам предварительно просматривать вещи, которые удаляются. Вы всегда можете вызвать его из командной строки, используя "%~dp0\EmptyFolderNuker.exe" %cd%.
Йерун Wiert Pluimers
1
@ rob-kam URL для "EmptyFolderNuker" больше не доступен.
PeterCo
@PeterCo Спасибо, исправлено.
Роб Кам
0

Если у вас установлен Cygwin , вы можете сделать это:

find -type d -exec rmdir {} \;
Энтони Джорджио
источник
4
Не обязательно. Это может не удалить каталоги только с пустыми подкаталогами. Возможно, вам придется изменить это. найти -тип d -print0 | так | xargs -0 rmdir
Райан Томпсон
Я никогда не знал о "TAC" раньше. Это действительно изящно!
Энтони Джорджио
1
Или используйте . Опция говорит что - то делать , как изменить порядок вывода - он идет до самых глубоких уровней каталогов, а затем работает свой путь обратно. find (starting-directory) -depth -type d ...-depthfind
G-Man
0

Если вы работаете в emacs (что делает эту платформу независимой), работает следующее:

(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)))))
Шон Оллред
источник
... Пожалуйста, скажите мне, что вам не придется вводить все это, чтобы выполнить это в emacs.
Хашим
1
@Hashim Идея состоит в том, что вы определили это в вашем init и затем связали с ключом. Технически я мог бы связать это, Dесли бы захотел, но, поскольку у меня нет общей потребности в этом, все, что я должен напечатать, - M-x *ded RETи все готово. (Если бы мне действительно приходилось печатать это каждый раз, вы абсолютно правы, что это было бы абсурдно - к счастью, это не так.)
Шон Оллред
Достаточно справедливо, это звучит более правдоподобно.
Хашим
Имеет ли M-x *ded RETкакое-либо значение или это случайно? Если последнее, как вы отслеживаете все ярлыки, которые вы назначили emacs? Достаточно ли запоминания или вам приходится искать их?
Хашим
1
@Hashim *ded- это сокращение от полного имени функции *-delete-empty-directories. Многие механизмы завершения (такие как ivy, тот, который я использую) понимают этот вид нечеткого соответствия. Что касается их запоминания ... Я просто не должен. Все функции, которые я определил, начинаются с *того, что я могу легко найти их, если они не привязаны к клавише. В противном случае, сам emacs скажет мне, есть ли более быстрый способ вызова функции. Если ничего не помогает, всегда есть apropos.
Шон Оллред
0

Объединение сообщений Гарета и G-Man:

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

Редактировать: Но это дало ошибку безопасности из-за 'C' в моей переменной PATH ... поэтому вместо этого:

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

Я не использую xargs, потому что кажется, что он имеет ограничение входной строки (около 1024 строк, я думаю?), Тогда как

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

просто продолжается до тех пор, пока у него есть вход. Оставьте подробный флаг '-v', если вы не хотите видеть результаты и / или хотите, чтобы он работал быстрее.

skeetastax
источник
0

Хм ... может быть, даже более простое решение:

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

Запустите это из папки, в которую вы хотите удалить пустые папки.

/ d - будет работать с папками, а не с файлами / r - будет возвращать подкаталоги

Даниэль Мошмондор
источник