22

I lost some files by using the mv command. I don't know where they are. They are not in the directory to which I intended to copy them.

Below is a transcript of what I did:

samuelcayo@CAYS07019906:~/Downloads/221-tp2-public-main$ cd
samuelcayo@CAYS07019906:~$ ls
Desktop  Documents  Downloads  GameShell  Music  Pictures  pratice  Public  Templates  Videos
samuelcayo@CAYS07019906:~$ mkdir tp2
samuelcayo@CAYS07019906:~$ ls
Desktop  Documents  Downloads  GameShell  Music  Pictures  pratice  Public  Templates  tp2  Videos
samuelcayo@CAYS07019906:~$ cd Downloads/221-tp2-public-main/
samuelcayo@CAYS07019906:~/Downloads/221-tp2-public-main$ ls
backup  copybash  Dockerfile               ntfy-1.16.0  packets.txt     README.md      restore        secret
cloud   data      Dockerfile_CAYS07019906  ntfy.zip     rapport-tp2.md  remplacer.sed  sauvegarde.sh  tail
samuelcayo@CAYS07019906:~/Downloads/221-tp2-public-main$ mv rapport-tp2.md tp2
samuelcayo@CAYS07019906:~/Downloads/221-tp2-public-main$ mv Dockerfile_CAYS07019906 tp2
samuelcayo@CAYS07019906:~/Downloads/221-tp2-public-main$ mv packets.txt tp2
samuelcayo@CAYS07019906:~/Downloads/221-tp2-public-main$ mv sauvegarde.sh tp2
samuelcayo@CAYS07019906:~/Downloads/221-tp2-public-main$ cd
samuelcayo@CAYS07019906:~$ cd tp2/
samuelcayo@CAYS07019906:~/tp2$ ls
samuelcayo@CAYS07019906:~/tp2$ ls -l
total 0
samuelcayo@CAYS07019906:~/tp2$ cd ..
6
  • 6
    IOW, you should have done mv rapport-tp2.md $HOME/tp2 (or equivalently mv rapport-tp2.md ~/tp2) and similarly for the rest, since you created the directory tp2 inside your home directory.
    – NickD
    Apr 24 at 2:25
  • 7
    The only file you can "restore" is sauvegarde.sh which is now ~/Downloads/221-tp2-public-main/tp2
    – Payam
    Apr 25 at 17:58
  • 3
    Is it wrong to be slightly amused that the one file you didn't lose is the one called "sauvegarde"? Apr 26 at 6:20
  • Related question about unintentional overwrites when using wildcards: cp and mv using wildcards and forgetting to specify a destination directory Apr 26 at 8:06
  • 4
    Note how you typed tp2/ when doing cd, where forcing its status to a directory is unimportant, but typed tp2 when doing mv, where it is important. Apr 26 at 23:57

3 Answers 3

81

You created a directory called tp2 in your home directory, i.e. you created the directory ~/tp2. You then changed into ~/Downloads/221-tp2-public-main and started to move files with mv.

Since you specified the target of each mv operation as tp2, and since tp2 was not a directory in your current directory, each file you moved was instead renamed tp2. You overwrote the file previously called tp2 each subsequent time you ran mv. In the end, the tp2 that you were left with is the file previously called sauvegarde.sh.

You would have avoided the loss of data by using ~/tp2/ as the target of each mv operation.

The ~ refers to your home directory, where you created your tp2 directory. The / at the end of the target path is not strictly necessary, but it makes mv fail gracefully if ~/tp2 is not a directory.

As for what you can do now to restore your lost files; consider restoring them from a recent backup if you don't have other copies of them lying around elsewhere.

4
  • I moved the off-topic discussion on the merits (or lack thereof) of making aliases to the -i versions of standard tools to chat..
    – terdon
    Apr 25 at 11:06
  • 19
    Note (if it's not already obvious) that making tp2/ the target of mv would also have avoided data loss precisely because it makes mv fail. Either get the directory right, or put / on the end, or both. Since you can't be sure you'll always get the directory right, but you can decide to always put / on the end, you should decide to always put / on the end. Apr 26 at 6:18
  • 8
    Also a good habit could be to use the tab-completion. When you notice that the target was not completed to tp2/ you notice that something is wrong - the target directory does not exist. Apr 26 at 7:58
  • 3
    Some people also like to create an alias from mv to mv -i so they can't accidentally overwrite a file with mv.
    – Stef
    Apr 26 at 12:14
28

The GNU implementation of the mv command (the one found on Ubuntu) has an explicit mv -t myDir option that checks that myDir is specifically an existing directory. This avoids the ambiguity between mv Source Dest (move to) and mv Source Directory (move into).

It also fixes the args order in constructs like find ... -print0 | xargs -r0 mv -t Dir --, where xargs by default appends args (so that placing the target directory last is not possible). Both these cases would have avoided your issue.

The mv -i option also offers protection against overwriting files accidentally.

8
  • 22
    And also make a habit out of a) using tab completion and b) using trailing slash in destination arguments
    – eckes
    Apr 24 at 19:37
  • 2
    @Stéphane Thanks for the edit. I came to GNU relatively recently, after too long on Solaris. Apr 24 at 20:39
  • That is why it is a good idea to use alias on mv, cp so that they are really mv -i, cp -i etc to avoid accidents like this. Apr 26 at 12:10
  • 5
    @stackoverblown I take the opposite view. I spent 15 years on customer sites working for a mainframe manufacturer, and then 30+ years as a contractor. Having basic commands configured to suit the personal prejudices of some cowboy SysAdmin is my idea of hell. Apr 26 at 20:20
  • @Paul_Pedant reminds me of one server I used where every text editor was linked to the sysadmin's (weird) personal favorite editor.
    – jrh
    Apr 27 at 2:02
2

Avoid doing this, interactively:

mv file1 dest
mv file2 dest
mv file3 dest

At least, avoid issuing multiple commands like this without checking the result of the first one:

mv file1 dest
ls -l dest # is there a dest, containing file1?

Instead, combine them into one:

mv file1 file2 file3 ... dest

If there are two or more files, then dest is interpreted as necessarily having to be a directory which exists. If it doesn't exist or isn't a directory, then mv fails:

mv: target 'dfsafsdfdf' is not a directory

If you issue multiple commands without checking their results, you may lose the benefit of whatever few safeguards they provide.

mv has a POSIX_standard -i option to avoid clobbering a destination which exists. You can include that in your interactive mv command via making an alias:

alias mv='mv -i'
1
  • You should probably explain that the alias is dangerous, because it encourages a dependency on it, making errors more likely when it's not available (e.g. in a sudo shell). May 6 at 21:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.