Elisp: Function to Copy/Delete a Dir Recursively (fixed)

By Xah Lee. Date: . Last updated: .

[ Addendum: this issue is fixed in emacs 23.2, released on . Specifically, emacs 23.2 has “copy-directory”, and recursive option is added to “delete-directory”.]

There lacks a function to copy and delete directories recursively.

in the elisp manual, the closest is: (info "(elisp)Create/Delete Dirs")

it would be good to have a function that copy a whole dir, and another for deleting whole dir.

Emacs does implement them in dired, or in eshell, apparently, but it's not easy to use them.

many scripting languages provide such functions, and is very convenient.

for deleting dir, perhaps this can be implemented:

(delete-directory dirname &optional recursive)

for copying dir, perhaps it can be modeled on copy-file:

(copy-file oldname newname &optional ok-if-exists time)

these should be perhaps few hours to implement for elisp developers, perhaps by just pulling existing implementation from dired or eshell.

Once implemented, they'd be standard functions in elisp manual. They would be great convenience for average elisp coders.

As a personal example, i needed to both copy dir recursively and also delete whole dir, in my use of elisp as a text processing lang. So far i've been just calling shell. Example:

(shell-command (concat "cp -R " fromDir " " toDir))
(shell-command (concat "find " destDir " -type d -name \"xx*\" -exec rm -R {} \\;"))

My script worked well in the past 2 years, but relying on unix shell has many complications. For example, recently i need my script to work on Windows. With Windows, there are many complications. For example, which unix shell you use, is it Cygwin, MSYS, their config, their path env var config in emacs, both are inter-related to which emacs distribution one is using (example: what shell runs when you do M-x shell). Then, recently in one emacs distro i'm trying out eshell (in hope that it perhaps more cross-platform than M-x shell or Lennart emacsW23's shell, cmd-shell, msys-shell), but discovered that eshell chocks on this standard Bash syntax:

find -name "*el" -exec rm {} \;

(reported in bug#4406. Doesn't work when called as shell-command neither. The solution is to replace \; with ';')

In short, something trivial turns out to be 5 or more hours to trying to get it work.

emacs + elisp is a great text processing lang, and one big advantage is that it is cross platform. So, all things considered, i think the suggestion in this report is a very good one, in particular its ratio of impact/ease-to-implement is relatively high.

if i eventually got a solution from looking into dired or eshell for copying/deleting dir, i'll update this report with code for draft implementation.


PS: this suggestion is reported to FSF as bug#4408, bug#4416.

Draft Implementation

Here's is a draft implementation. Tested and used to replace my elisp scripts that relied on unix cp.

(defun copy-directory-recursive (source-dir dest-dir)
  "Copy a whole directory SOURCE-DIR to DEST-DIR.
Note, the semantics of source-dir dest-dir is different from the
unix “cp” utility.  In unix's “cp -R”, if dest-dir exists, it'll
copy source-dir itself, else, just source-dir's children.

In copy-directory-recursive, it always copy source-dir's children.

In both, the dest-dir may or may not exist. If not, it'll be
created. However, dest-dir's parent must exist.

This function is based on dired-copy-file-recursive.  Behavior
about linked files, time stamp, etc, are from that function.

WARNING: when copying to a existing dir with existing files, old
files does not seem to get over-written.  This is a major
bug… needs research.  Do not use this function."

  (require 'dired-aux)
  (dired-copy-file-recursive source-dir dest-dir nil nil nil 'always)

Emacs Modernization

  1. Simple Changes Emacs Should Adopt
  2. Why Emacs Keys are Painful
  3. Problems of the Scratch Buffer
  4. M-key Notation vs Alt+key Notation
  5. Menu Problem
  6. Mode Line Problem
  7. cua-mode Problems
  8. kill-buffer Induces Buffer Accumulation
  9. Emacs Form Feed ^L
  10. Inconsistency of Search Features
  11. Single Key to Delete Whole Line
  12. Emacs HTML Mode Sucks
  13. Emacs Does Not Support Viewing Images Files In Windows
  14. Emacs Spell Checker Problems
  15. Adopt HTML as Texinfo Replacement
  16. Support HTML Mail
  17. Problems of “man” Command
  18. Emacs Lisp Mode Syntax Coloring Problem
  19. Emacs Ahk Mode Problems
  20. Problems of Emacs's Manual
  21. Problems of Emacs's Manual; Examples
  22. Emacs: Have You Read Emacs Manual?
  23. Elisp: Ban Syntax Table
  24. Emacs: Make elisp-index-search use Current Symbol
  25. Emacs: Usability Problems of Mode Documentation
  26. Emacs GNU Texinfo Problems; Invalid HTML
  27. A Record of Frustration in IT Industry; Disappearing FSF URLs, 2006
  28. Emacs Manual Node Persistency Issues
  29. Emacs: dired-do-query-replace-regex Replace ALL (fixed)
  30. Problems of Emacs Supporting Obsolete Systems
  31. Elisp: Function to Copy/Delete a Dir Recursively (fixed)
  32. Thoughts on Common Lisp Scheme Lisp Based Emacs
  33. Text Editors Popularity and Market Research
  34. Text Editor's Cursor Movement Behavior (emacs, vi, Notepad++)
  35. GNU Emacs Development Inefficiency
  36. Emacs Dev Inefficiency and Emacs Web 2.0?
  37. Letter-Case Commands Usability Problems
  38. Emacs: Select Line, between Quotes, Extend Selection
  39. Emacs: isearch Current Word
  40. Suggestions on Line Wrap Commands
  41. Emacs: Single Key to Delete Whole Line
  42. Emacs Undo and Emacs Cult Problem

If you have a question, put $5 at patreon and message me.
Or Buy Xah Emacs Tutorial
Or buy a nice keyboard: Best Keyboards for Emacs


Emacs Lisp