I am trying to get a directory
to replace an existing folder
but can't get it done with mv - I believe there's a way and I just don't know it (yet). Even after consulting the man page and searching the web.
If /path/to/
only contains directory
, the following command will move /path/to/directory
(vanishes) to /path/to/folder
mv /path/to/directory /path/to/folder
It is basically a rename, which is what I try to achieve.
But if /path/to/folder
already exists, the same command moves the /path/to/directory
to /path/to/folder/directory
.
I do not want to use cp
command to avoid IO.
Instead of using cp
to actually copy the data in each file, use ln
to make "copies" of the pointers to the file.
ln /path/to/directory/* /path/to/folder && rm -rf /path/to/directory
Note this is slightly more atomic than using cp
; each individual file appears in /path/to/folder
in a single step (i.e., there is no chance that /path/to/folder/foo.txt
is ever partially copied), but there is still a small window where some, but not all, files from /path/to/directory
have been linked to folder
. Also, the rm -rf
is not atomic, but assuming no one is interested in directory
, that's not an issue. (Although, as files from /path/to/directory
are unlinked, you can see changes to the link counts of files under /path/to/foldoer
changing from 2 to 1. It's unlikely that anyone will care about that.)
What you think of as a file is really just a file system entry to an otherwise anonymous file managed by the file system. For example, consider a simple example.
$ mkdir d
$ cd d
$ echo hello > file.txt
$ cp file.txt file_copy.txt
$ ln file.txt file_link.txt
$ ls -li
total 24
12890456377 -rw-r--r-- 2 chepner staff 6 Mar 3 12:46 file.txt
12890456378 -rw-r--r-- 1 chepner staff 6 Mar 3 12:47 file_copy.txt
12890456377 -rw-r--r-- 2 chepner staff 6 Mar 3 12:46 file_link.txt
The -i
option adds each entries inode number (the first column) to the output; an inode can be thought of as a unique identifier for a file. In this output, you can see that file_copy.txt
is an entirely new file, with a different inode than file.txt
. file_link.txt
has the exact same inode, meaning that file.txt
and file_link.txt
are simply two different names for the same thing. The number just before the owner is the link count; file.txt
and file_link.txt
both refer to a file with a link count of 2.
When you use rm
, you are just removing a link to a file, not the file itself. A file is not removed until the link count is reduced to 0. To demonstrate, we'll remove file.txt
and file_copy.txt
.
$ rm file.txt file_copy.txt
$ ls -li
total 8
12890456377 -rw-r--r-- 1 chepner staff 6 Mar 3 12:46 file_link.txt
As you can see, the only link to file_copy
is gone, so inode 12890456378 no longer appears in the output. (Whether or not the data is really gone is a matter of file-system implementation.) file_link.txt
, though, still refers to the same file as before, but now with a link count of 1, because file.txt
was removed.
Links to a file do not have to appear in the same directory; they can appear in any directory on the same file system, which is the only caveat using this trick. ln
will, IIRC, give you an error if you try to create a link to a file on another file system.