67

I always get messed up when need to use cp or mv: "do I need -R option when working with dir?" In GNU coreutils cp does need -R and mv doesn't.

I just can not find any reason why cp needs -R option for copying dirs and mv doesn't. I think that cping dirs without -R (but behaving recursively like there's -R and like mv 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?

0

3 Answers 3

46

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.

10
  • is mving from one file system to another the same "just change the name in the directory entry"?
    – wobmene
    Aug 22, 2012 at 13:02
  • 5
    No, 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.
    – derobert
    Aug 22, 2012 at 13:18
  • 9
    I can tell you, from direct experience not speculation, that classical mv did not support cross-device moves. It used to just try a rename() 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!
    – Alan Curry
    Aug 22, 2012 at 19:16
  • 5
    @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.
    – derobert
    Aug 22, 2012 at 20:12
  • 1
    @derobert, it didn't (cross-filesystem mv worked only for individual files on BSD 4.2 on VAX).
    – vonbrand
    Jan 23, 2013 at 16:43
22

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 mved, 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.

4
  • 2
    That's right, I just was thinking of cp and mv 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.
    – wobmene
    Aug 24, 2012 at 8:11
  • 1
    Well structured, reasoned response.
    – Spedge
    Aug 28, 2012 at 18:34
  • 1
    @RuslanKhusnullin Your coffee analogy works for cp and mv 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.
    – jw013
    Jan 18, 2013 at 20:02
  • 1
    @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.
    – wobmene
    Jan 23, 2013 at 20:58
6

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .