Idiocy Of Unix Copy Command

By Xah Lee. Date:

[2010-11-27 this article may be completely incorrect. Pending correction]

I'm coding in emacs lisp to create a zipped version of a online book for users to download and read off line. 〔see Elisp Lesson: Zip Your Website For Reader Download〕 In the project, it requires me to copy several directories programtically.

Originally, i thought the copying dirs part would be something simple, like making few unix shell calls “cp -R fromDir toDir”, one for each source dir, where fromDir and toDir are full paths. However, it turns out the problem is slightly more complex. A 5 minutes job that ends up a couple of hours, due to, a brainlessness of the unix cp command.

Directories are abstractly a tree. Copying directories is like grafting a tree from one branch into another branch. To begin, we are given two spec: the source node and a destination node. The source node by definition is a existing node (i.e. existing dir), otherwise the copying won't make sense. However, the destination spec can be a node that doesn't exist, or its parent doesn't exist, or several levels of parents doesn't exist. When the destination spec has missing nodes, we can consider creating them as part of the grafting process, or we can consider it as a error. Either choices may be a good design decision. However, the unix “cp -R” is a faak up.

The unix “cp” tool's “smart” behavior (when using the option “-R”) is stupid in 2 way.

Emacs Lisp Semantics

Emacs Lisp does not have a copy dir function, however, it can be found in one of the dired package bundled with emacs.

To use it, call it like this:

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

This function's behavior is different from unix's “cp -R”. With dired-copy-file-recursive, it ALWAYS copy the source dir's children.

This is a better design, because it has precision, which in turn makes it easier to use, and with more flexibility.

Other Tool's Copy Semantics

TODO… write about the behavior of the following tools:

see