Why unix mv program doesn't need -R (recursive) option for directories but cp does need it?
Solution 1
A directory is (conceptually) a special "file" which contains a list of names, and the inode numbers those names point to. Some of names can be subdirectories. There is a special entry ..
which points to the parent directory.
So, its clear, changing the name of a file is easy: you just change the name in the directory entry, nothing else. This holds whether the file is actually a file, or is a "file" used to store another directory's contents. Indeed, the same rename
syscall does both.
Copying, however, is a much less trivial operation. You could just copy the directory "file", but then you'd have two directories where are the files are the same (they'd be hardlinks). If you had a system that allows hardlinks to directories, those would be to, but since no modern system allows that, at least to non-root, you have to do that copy for each subdirectory. You can actually ask cp
for this behavior with cp -lR
: -l
for hard link, -R
for that recursion.
But leaving everything linked is likely not what you want. Instead, you want cp
to copy each file. That's a fairly expensive operation: each file must be read into memory, and written back out to disk in a second location. It actually takes several syscalls, to open, read, write, and close the files, and that has to be repeated for each file.
Traditional filesystems work this way on disk, too. There isn't any way to copy a bunch of files, other than to go through each one individually and copy it, and those are the types of filesystems that were in use when the basic command line utilities were designed.
Solution 2
Let me start by asking another question:
What is the difference between cp
and cp -R
?
Well, without the -R
flag, it's only possible to copy files, because it's rather unusual that someone wants to non-recursively copy a directory: A non-recursive copy would just result in a second name for the directory, pointing to directly the same directory structure. Because that's rarely what people want, and there is actually a separate program that does this (ln
), a non-recursive copy of directories is not allowed.
What then could be the difference between mv
and mv -R
?
mv a b
just renames a single entry in the directory, so if a directory is mv
ed, its contents are automatically also moved. In that sense, mv
already provides the recursive property, i.e. the "renaming" of all entries in the renamed directory, e.g. from a/1
to b/1
. A mv
that does not do that, i.e. which renames a directory a
to b
, but keeps a/1
as a/1
, is not what people understand when they refer to moving something: When you move a cupboard, the contents of the cupboard are moved as well. That other operation, moving a directory without its contents, is also already available, it's called mkdir
.
Solution 3
Usually when I'm messed up with Unix logic I look at Plan9 to see how Unix inventors' implemented the same tasks years later without stucking on backward compatibility.
So Plan9 offers cp
and mv
tools to operate with files only.
`cp f1 f2` creates f2 and copies f1's contents into it.
`mv f1 f2` renames f1 to f2 if f1 and f2 are in the same dir
does `cp f1 f2 && rm f1` else
can rename dirs (`mv d1 d2`) but will not move dir to another dir.
For copying a dir there's dircp
that is really @{cd fromdir && tar c .} | @{cd todir && tar xT}
(rc shell syntax)
For moving a dir I think there's only dircp d1 d2 && rm -r d1
I think this decision to limit cp
and mv
for file operations only (not dirs) brings more clearness to disk operations and using tar
for copying file trees is very comfortable for understanding and scripting.
Related videos on Youtube
Volodymyr Machula
Updated on September 18, 2022Comments
-
Volodymyr Machula almost 2 years
I always get messed up when need to use
cp
ormv
: "do I need-R
option when working with dir?" In GNU coreutilscp
does need-R
andmv
doesn't.I just can not find any reason why
cp
needs-R
option for copying dirs andmv
doesn't. I think thatcp
ing dirs without-R
(but behaving recursively like there's-R
and likemv
does) wouldn't cause any problems except breaking someone's habits on using the tool.Do you know any explanation? May be it had a reason long time ago?
Additional question: why don't coreutils developers make
cp
copy dirs recursively by default? -
Volodymyr Machula almost 12 yearsis
mv
ing from one file system to another the same "just change the name in the directory entry"? -
derobert almost 12 yearsNo, cross-filesystem is the same as a copy + delete (indeed, the
rename
syscall will fail for cross-filesystem). Not sure if, historically,mv
even supported cross-fs moves. -
Volodymyr Machula almost 12 yearsso you want to say that
mv
tool was created just for renaming files? and later it was modified to support cross-fs moves with copy+remove? then why don't coreutils developers makecp
copy dirs recursively by default? isn't it a good UX improvement too? -
Alan Curry almost 12 yearsI can tell you, from direct experience not speculation, that classical
mv
did not support cross-device moves. It used to just try arename()
and print an error message if it failed. I still remember the shocked feeling I had the first time I accidentally used the new feature. Why is this mv taking so long? Oh, it's doing a recursive copy that I didn't intend! -
derobert almost 12 years@RuslanKhusnullin Command-line options to common commands are very hard to change, due to their use in shell scripts. Someone may be depending on the current refuse-to-copy-dirs behavior of cp. The cross-fs stuff was probably judged less likely to cause breakage, though as you can see, it still surprised Alan.
-
Alan Curry almost 12 yearsAfter a brief adjustment though, I'm thankful for it.
-
Volodymyr Machula almost 12 yearsI have posted my explorations as an answer (it was too long for a comment). Finally I think there could be two comfortable (IMHO) behaviours: 1. make
cp
andmv
work with files and dirs -- just do what the name of command says 2. makecp
andmv
work with files only and createdircp
anddirmv
for manipulating dirs recursively -
Volodymyr Machula almost 12 yearsThat's right, I just was thinking of
cp
andmv
as operations that they are named: 'make a copy' and 'move'. So if I want to make a copy of a cup of coffee, I'd expect to have another cup of coffee with the same filling (coffee drink). The problem is that the tools are not intended for 'usual people' but for nerds who are aware of disk and file system structure, not virtual entities like files and dirs of files. -
Spedge almost 12 yearsWell structured, reasoned response.
-
jw013 over 11 years@RuslanKhusnullin Your coffee analogy works for
cp
andmv
too - it does not require any level of "nerdness" to understand, just basic common sense. A true copy of a cup of coffee is not an empty cup - you have to recursively copy not only the cup, but all of its contents (the coffee) too. However, when you move a cup of coffee you don't have to move the contents separately - the contents move with the container naturally. -
vonbrand over 11 years@RuslanKhusnullin, it's too late for that now :-(
-
Volodymyr Machula over 11 years@jw013 You've impressed me with "when you move a cup of coffee you don't have to move the contents separately", it really makes sense, thank you. But it's another layer of abstraction. I think you mean "treat a file as an inode" while I think of files like of bytes sequences without meta-information.
-
Razzlero over 11 years@RuslanKhusnullin I think the proper way to go about this is to add a "classic" command line option and for you to alias using it when using cp and mv.