4

That is, if I have

-empty-dir-a/
-nonempty-dir-a/
  -empty-dir-a/
    -empty-dir-a/
  file-a
file-a
file-b

I would like

-nonempty-dir-a/
  file-a
file-a
file-b

I'm aware that there are many OS-specific solutions to this, but I'd like to stick to elisp, ideally :).

2 Answers 2

3

You could just use the find tool.

M-! find . -empty -type d -delete return

Here it is wrapped in a function that confirms the delete:

(defun delete-empty-dirs ()
  (interactive)
  (let ((dirs (split-string (shell-command-to-string "find -X $(pwd) -empty -type d") "[ \n]" t)))
    (when (yes-or-no-p (format "Delete %d empty directories? " (length dirs)))
      (with-temp-buffer (shell-command "find -X $(pwd) -empty -type d -delete")))))
4
  • Lovely on *nix, but Windows (et al.) don't have a find command. There's always Cygwin for those how are allowed to install it, but it doesn't come default. Commented May 6, 2015 at 19:12
  • 1
    Make your life easier on windows with: mingw.org
    – InHarmsWay
    Commented May 7, 2015 at 22:49
  • @InHarmsWay I have Cygwin actually, after trying MinGW and finding it insufficient. …Cygwin is also insufficient. :( Commented May 8, 2015 at 0:15
  • 1
    @SeanAllred Perhaps it's Windows that's insufficient. 😊 I was happy enough to find Mingw had a decent find and grep, and other basic commands. But yes, it's all more painful than it should be.
    – InHarmsWay
    Commented May 9, 2015 at 4:03
2

This requires the following functions from f.el, available from MELPA:

  • f-directories returns a list of directories in the given directory
  • f-entries returns all files and folders in the given directory
(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))))))
3
  • Presumably, this is the library f.el that you are requiring.
    – Drew
    Commented May 6, 2015 at 15:53
  • @Drew correct – I thought it was sortof common knowledge to look for foo.el when foo is required (like \usepackage{foo} needs foo.sty in LaTeX). Commented May 6, 2015 at 16:48
  • @Drew Edited for clarity :) Commented May 6, 2015 at 17:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.