Elisp Lesson on file processing (make downloadable copy of a website)

xahlee at gmail.com xahlee at gmail.com
Sun Jul 6 10:05:09 CEST 2008

In this week i wrote a emacs program and tutorial that does archiving
a website for offline reading.
(See http://xahlee.org/emacs/make_download_copy.html )

In the process, i ran into a problem with the unix “cp” utility. I've
been a  unix admin for Solaris during 1998-2004. Even the first time i
learned about cp, i noticed some pecularity. But only today, i thought
about it and wrote it out exactly what's going on.

Here's a excerpt from my emacs tutorial above regarding the issue.

Copying a bunch of directories seems a trivial operation, but it
actually took me a couple hours to arrive at the final code, due to
the exact requirement of directory paths, and the unix “cp” tool's
lack of precision and flexibility.

Originally, i thought the code would be something simple like several
“(shell-command (concat "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.

Suppose the source dir is “/Users/xah/web/emacs” and dest dir is “/
Users/xah/web/diklo/xahtut/emacs” and i want all branches under the
source dir copied into the dest dir.

If you do “cp -R /Users/xah/web/emacs /Users/xah/web/diklo/xahtut/
emacs” with both xahtut and xahtut/emacs doesn't exist, then this
error results: “cp: /Users/xah/web/diklo/xahtut/emacs: No such file or

If you do “cp -R /Users/xah/web/emacs /Users/xah/web/diklo/xahtut/
emacs” with xahtut/emacs exists, then you got “/Users/xah/web/diklo/
xahtut/emacs/emacs”, which is not what i want.

If you do “cp -R /Users/xah/web/emacs /Users/xah/web/diklo/xahtut”
with xahtut doesn't exist, it results in all branches of emacs in
xahtut, which is wrong.

Only when you do “cp -R /Users/xah/web/emacs /Users/xah/web/diklo/
xahtut” with xahtut exists, you get the correct result with the new
dir “/Users/xah/web/diklo/xahtut/emacs” having all branches of the
original dir.

So, the solution is to first create all the parent dirs of the dest
dir, but without the dest dir node itself. Then, do a cp to the first
parent of dest dir.

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 or file),
otherwise the copying won't make sense. However, the destination spec
can be a node that doesn't exist, or its parents 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.

The unix “cp” tool's behavior is mathematically inconsistent. When the
destination node exist, the source node will become new children of
destination node. When the destination node does not exist (but its
parent exists), “cp” will create the node, and copy only the children
of the source node to it. When the destination node doesn't exist and
its parent doesn't exist neither, then “cp” considers it a error.

Related readings:

• The Nature of the “Unix Philosophy”

∑ http://xahlee.org/

More information about the Python-list mailing list