26

Say I have a directory /hello.

Then I do mv /hello /hello2.

Am I moving /hello into /hello2/hello? Or am I moving /hello to /hello2?

It seems that when I do something like this, I get inconsistent results.

dcharles
  • 107
user4951
  • 10,519
  • 1
    In what case is the result inconsistent? It seems whenever the target directory exists it moves into the target directory, otherwise it gets renamed. – jmathew Jan 15 '13 at 17:27
  • That is inconsistent. The same command should do the same thing. That means the command is ambiguous. – user4951 Jan 15 '13 at 18:28
  • That's not really inconsistent because it acts consistently within context. Although I can see how it's confusing but the more I think about it, the command has to be that way in order to work for all scenarios. – jmathew Jan 15 '13 at 18:37
  • I would rather say that's how it is designed and its also logical..if you use mv with files it does the same thing.just renaming.but with mv with directories It's not good to delete the whole directory with subdirectory because of one mv command which is not safe. so it is moved as test1/test2. but if you still want to acheive it write a alias which check whether the parameter given is directory and then do rm -rf the directory and uses the mv command but use it at your own risk. – harish.venkat Jan 15 '13 at 18:46
  • I suspect your example is based on misremembering something that has happened in the past, based on "It seems that I do something like this". If both /hello and /hello2 are directories, then I've noticed that cp /hello /hello2 is the one that's inconsistent. Depending on what combination of trailing slashes are there, sometimes the contents of /hello are copied into /hello2, and sometimes the directory itself is copied in. – Izkata Jan 15 '13 at 19:27
  • I don't remember where I saw it, but when they designed Plan 9 (sort of a successor to UNIX) they split moving from renaming commands specifically to address situations like this. – Joe Jan 19 '13 at 01:19
  • If the target is a directory, the source gets moved into it. If it is a plain file, it gets overwritten. – vonbrand Jan 21 '13 at 20:36

3 Answers3

22

mv a b attempts to move a into b if b is a directory or a symlink to a directory. Otherwise, it will rename (or copy and delete if on different file systems) a to b.

To get a consistent result to move a file into a directory, you can do:

mv file dir/.

If dir doesn't exist, you'll get an error, and it won't rename file to dir.

mv file dir/ would also work, but not if file itself is of type directory and dir itself doesn't exist.

If, on the other hand, you want to do a rename without having to worry if the destination file exists as a directory or not, with GNU mv, you can do:

mv -T file dest

In that case, file will not be moved into dest if dest is a directory. However, if both file and dest are directories and dest is empty, file will be renamed to dest (and the original dest removed). If both are directories and dest is non-empty, mv -T will complain.

Same, if file and dest are not directories (and that includes symlinks including symlinks to directories), file will be renamed to dest (though you will get a prompt if you don't have write permission to dest), and the original dest will be removed. There's a difference with mv file dest in the case where dest is a symlink to a directory. With -T, file is renamed to dest, but without -T, file is moved into the directory pointed to by dest.

So to sum up, after mv -T file dest, either file will have been renamed to dest or you'll get an error message (or a prompt). If the command succeeded, the original dest, if it existed beforehand will have been removed.

  • Your first example doesn't work for me: To make sure a file is moved into a directory I need mv file dir/. (with dot). Maybe it's because GNU mv has had its behavior changed since you wrote this... – philipp2100 Feb 17 '22 at 16:29
  • @philipp2100, see edit. I suspect you're refering to the case where the source file is a directory which I hadn't thought of. – Stéphane Chazelas Feb 19 '22 at 20:18
  • Thanks for the edit! I thought it was mostly about the case where source is a directory, so my comment didn't stress that as clear as it could have, but I think your edit quite cleared things up. However, existing targets are not a problem for me in the target/ case: mv a empty/ will just move a into empty, also if empty is a symlink, and dangling symlinks as targets will fail, although for empty/ (unlike empty or empty/.) mv asks for confirmation first, which can be undesirable. – philipp2100 Feb 22 '22 at 08:49
  • @philipp2100, yes, you're right, not sure what I was thinking. Fixed now. – Stéphane Chazelas Feb 22 '22 at 09:29
16

This is entirely dependent of if there was already a directory named /hello2 already in existence or not.

If /hello2 exists AND is a directory, then mv will always move /hello to /hello2/hello.

If /hello2 does not exist, then mv will always rename /hello to /hello2.

If /hello2 exists AND is a file, you will get an error, cannot overwrite non-directory 'hello2' with directory 'hello'.

Don Simon
  • 503
3

I tried these

mkdir test1
mv -v test1 test2
output:`test1' -> `test2'
mkdir test1
mv -v test2 test1
output: `test2' -> `test1/test2'
touch test2
output:mv: cannot overwrite non-directory `test2' with directory `test1'

hope this explains everything. -v is verbose mode.