Why doesn’t `mv file /dir` move the file to a subdirectory of the current working directory?

Solution 1:

Provided a directory with this name doesn’t exist, you renamed the file to openvpn located in your root directory /. To revert this, run:

sudo mv /openvpn /etc/MyFile.conf

If the directory did exist you moved the file inside it, then the reversion is:

sudo mv /openvpn/MyFile.conf /etc/

To move it to an existing subdirectory of the current directory you can run any one of these – those use relative paths:

mv MyFile.conf openvpn
mv MyFile.conf openvpn/
mv MyFile.conf ./openvpn
mv MyFile.conf ./openvpn/

. is a link to the current directory, so ./ at the beginning of a path means “in this directory”. The slash at the end means that openvpn is a directory and you want to move the file inside it. If you don’t provide it, the file will be moved into it if a directory with this name exists, else the file will be renamed to openvpn. With a / at the end, mv will warn you if the directory is missing and not rename, so that’s the secure way if you don’t want to rename.

If your path begins with / on the other hand it’s an absolute path regardless of the current working directory, it’s always relative to the root directory /. Using absolute paths for both file and destination your command would look like this:

mv /etc/MyFile.conf /etc/openvpn
mv /etc/MyFile.conf /etc/openvpn/

Further reading

  • What is a full path name?
  • Absolute / canonical / relative paths on Unix & Linux

Solution 2:

You need to use

me@mylaptop:/etc$ sudo mv MyFile.conf openvpn/

to move the MyFile.conf file into the openvpn sub-directory of /etc/.

On the other hand

me@mylaptop:/etc$ sudo mv MyFile.conf /openvpn

would move the file to the / directory as openvpn (i.e. rename as openvpn) instead (assuming /openvpn directory doesn't exist).

Solution 3:

When you move a file, you tell the OS the directory into which you want to put it, or the new path you want to give it.

You told the OS "/openvpn". So it's going to do exactly that - check if /openvpn exists (meaning an object called "openvpn" located in the root directory) and is a directory, and if so move your file into it, or else if /openvpn is a file or doesn't exist, rename and move your file so it's now accessible as /openvpn.

What you wanted it to do was move it to within a directory "openvpn", which is to be found in your current directory, not one that's in the file system root directory (which is what the leading "/" signifies). So you had to point to that dir in the move command, not to absolute path "/openvpn". Any of these will work:

  • mv MyFile.conf openvpn - look in my current dir for this "openvpn"
  • mv MyFile.conf /etc/openvpn - look for absolute path /etc/openvpn
  • mv MyFile.conf openvpn/ - look in my current dir, for a dir called openvpn
  • mv MyFile.conf ./openvpn - makes the "current dir" even more obvious

Short version - you probably used "/" to mean "my current directory", therefore "/openvpn" to mean "openvpn which is in my current directory". But a leading "/" only ever means "the root directory", so "/openvpn" meant "openvpn in the root directory". What you needed was simply to use "openvpn" or "openvpn/", meaning "openvpn in my current directory".

Solution 4:

Any path that starts with / is an absolute path, not relative.

If all paths were always relative to the current directory, how would you cd /etc in the first place? You'd have to cd ../../../../../etc and hope that was enough levels of .., or just keep doing cd .. until you got to the root directory.

Or you'd need some other syntax to express absolute paths. But Unix decided on / meaning absolute, anything else being relative to the process's current working directory. So mv MyFile.txt openvpn would work.


And no, it wouldn't work well to infer absolute vs. relative from files existing or not. We wouldn't want mkdir system calls to treat paths differently from chdir or rename system calls, and making the mv program do it just leaves room for inconsistency between mv and some other program that takes an output filename.

mv is already special because when the rename() destination is a directory, it appends the source filename to that destination directory and tries again. But notice that one simple implementation strategy relies of the first rename() system call failing with EEXIST or EISDIR. So we have to know whether a path is relative or absolute before checking the filesystem.

(Early Unix ran on slow computers, where extra checks if a directory existed could mean extra I/O if it wasn't cached, or more pressure on directory caching. But I think sanity / correctness arguments are sufficient to explain why your first guess wasn't a plausible way for the system to work, without resorting to historical efficiency arguments.)