Why unix mv program doesn't need -R (recursive) option for directories but cp does need it?

87,638

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

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.

Share:
87,638

Related videos on Youtube

Volodymyr Machula
Author by

Volodymyr Machula

Updated on September 18, 2022

Comments

  • Volodymyr Machula
    Volodymyr Machula almost 2 years

    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?

  • Volodymyr Machula
    Volodymyr Machula almost 12 years
    is mving from one file system to another the same "just change the name in the directory entry"?
  • derobert
    derobert almost 12 years
    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.
  • Volodymyr Machula
    Volodymyr Machula almost 12 years
    so 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 make cp copy dirs recursively by default? isn't it a good UX improvement too?
  • Alan Curry
    Alan Curry almost 12 years
    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!
  • derobert
    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
    Alan Curry almost 12 years
    After a brief adjustment though, I'm thankful for it.
  • Volodymyr Machula
    Volodymyr Machula almost 12 years
    I 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 and mv work with files and dirs -- just do what the name of command says 2. make cp and mv work with files only and create dircp and dirmv for manipulating dirs recursively
  • Volodymyr Machula
    Volodymyr Machula almost 12 years
    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.
  • Spedge
    Spedge almost 12 years
    Well structured, reasoned response.
  • jw013
    jw013 over 11 years
    @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.
  • vonbrand
    vonbrand over 11 years
    @RuslanKhusnullin, it's too late for that now :-(
  • Volodymyr Machula
    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
    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.