20

I'm learning unix commands from a UNIX Tutorial for Beginners at surrey.ac.uk where I found a weird way to move a file. In particular, I have the folder unixstuff in the home directory, inside the unixstuff there is the folder backups and the files Caiti.txt and Caiti.bak.

According to the above link, to move the Caiti.bak file from unixstuff to backups I have to make sure that the current directory is unixstuff and I have to run the command:

mv Caiti.bak backups/.

Could you explain the meaning of the /. characters, please? The dot means current directory (unixstuff in this case). If I run the command:

mv Caiti.bak backups

it works anyway.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Gennaro Arguzzi
  • 311
  • 1
  • 7
  • 6
    “The dot means current directory (unixstuff in this case).” Not quite, it means the directory at whatever point in the path it is — the current directory when it’s on its own, the `backups` directory when it comes after that as in `backups/.`. It’s an actual directory in each directory, pointing to the directory containing it. – Stephen Kitt Aug 26 '20 at 08:04
  • Hello @StephenKitt thank you very muc for your explanation. Now it's more clear. – Gennaro Arguzzi Aug 26 '20 at 08:15
  • 4
    Modern versions of `mv` (and some similar commands) have an additional option like `mv -t target file ...`. This has two benefits. (a) It explicitly checks target is a directory, avoiding the rename-file ambiguity. (b) It is suitable for use with `xargs` because the file list comes last, not the target directory name. – Paul_Pedant Aug 26 '20 at 10:26
  • Adding to what @StephenKitt said, on older filesystems, _`.` is actually a directory entry on disk_. The special handling of `.` in POSIX compliant systems was inherent to the filesystem structure itself originally, not the VFS. However, many newer filesystems do not store physical `.` (and `..`) entries in the directory, instead generating them for `readdir()` calls as-needed, though that's still part of the FS itself and not the VFS layer in most cases (though the VFS is usually responsible for normalization of stuff like `./././.`). – Austin Hemmelgarn Aug 27 '20 at 01:52
  • The second example will "work" if the directory `backups` doesn't exist yet, but it won't do what you were expecting, and would be disastrous in the long run. – Shadur Aug 28 '20 at 07:22

1 Answers1

46

TL;DR

This forces the destination to be a directory that already exists or the command to fail without effect and is used as a fail-safe.


The meaning of .

Every directory in typical Unix/Unix-like filesystems include two special directories: one referencing the directory where it is: . and one referencing the parent directory of where it is: .. (allowing to move back in the hierarchy of directories). They are relative to where they are found. So the directory . inside a directory named backups references backups. To tell it otherwise, when there's a directory named backups, backups/. is equivalent to backups.


Different behaviors with the source or destination being a file or directory

  • If the directory exists, the two commands will have the same effect: when the target is a directory mv will move source(s) to that directory. That's the expected outcome.

  • If the target backups is a file instead of the directory:

    • 1st case will fail with the error Not a directory
    • 2nd case will rename Caiti.bak and overwrite backups
  • If the target doesn't exist:

    • 1st case will fail with No such file or directory
    • second command will rename the file Caiti.bak into the file backups, leading to the previous case and possible loss of data the next time it happens.

That's good practice to append /. to a directory target supposed to be existing and abort a script at an error from this.

All these cases would work the same when only appending / if the source is a file rather than a directory.

If we can't assume this, this example where the source is a directory:

mv somedirectory targetnothere/

would not fail (and somedirectory will be renamed instead of being put into targetnothere or abort). The extra . will make this case fail too:

$ mv somedirectory targetnothere/.
mv: cannot move 'somedirectory' to 'targetnothere/.': No such file or directory
A.B
  • 31,762
  • 2
  • 62
  • 101
  • 5
    To remove the need for these sublte hacks (and path manipulations if paths are supplied from elsewhere), `mv` had a `-t` switch that has the same effect regardless of how the target is written. – ivan_pozdeev Aug 27 '20 at 03:24