I moved all files from one directory using mv
and accidentally made a typo in the target location path.
The system returned a message that the directory does not exists, but my files from source directory got erased.
Is that a bug? Should moving files to a nonexistent location erase the files being moved? (This is on Ubuntu 18.04.2 LTS.)
The specifics were:
- Created
test.txt
file. - Moved the file to
/ben
withsudo
. - The file disappeared.
/ben
does not exist.
The commands and output were:
ben.b@c-w46:~/Desktop/test-folder$ sudo mv test.txt /ben
ben.b@c-w46:~/Desktop/test-folder$ cd /ben
bash: cd: /ben: Not a directory
In the command you actually ran, you didn't lose anything! It succeeded at renaming
test.txt
to/ben
. Assumingtest.txt
was a regular file, so is the new/ben
(they're the same file, after all).The reason you see
bash: cd: /ben: Not a directory
is what it says on the tin:/ben
is not a directory. You can still access the file.If you want to avoid that sort of mistake and force
mv
to fail if the destination isn't a directory, write a trailing/
on it or use-t dir
. For example, any of these would've prevented the (very minor!) problem you experienced (withsudo
as necessary):Information about the general situation described in your question--about losing files by attempting to move them--and what can and can't go wrong follows.
As Rinzwind says, moving files to a nonexistent destination directory shouldn't cause data loss when you attempt it using a single
mv
command. But it could happen if you ranmv
more than once, such as in a shell loop.For example, suppose I have:
To move all those files into
dest
, I should pass all their names tomv
, in a command likemv file*.txt dest/
ormv file*.txt dest
. In either case--that is, whether or not I write the target directory name with a trailing slash--this does the right thing. And in either case, if I misspell the target directory name (say, by writingdst
instead) I get an errormv: target 'dst' is not a directory
and no data are lost.However, suppose I were to misspell
dst
, omit the trailing/
, and run multiplemv
commands. That would be bad, because when the destination ofmv
is a regular file,mv
replaces it!This is why many people prefer always to write destination directories with a trailing
/
inmv
:You can use
mv -i
to ask you before overwriting, ormv -n
to silently not overwrite. Otherwise,mv
only ask you before overwriting if the destination is a read-only file. One reason to consider this is that it covers other cases, likemv file01.txt dest/
where you didn't realizedest/file01.txt
existed and didn't want to overwrite it.You can also use
-t dest
instead of writingdest
at the end of the command, e.g.,mv -t dest file*.txt
. This refuses to operate ifdest
is a regular file, regardless of whether or not you write a trailing/
.Using an automated mechanism to run multiple such commands can gravely compound the problem. For example, as written the command
for f in file*.txt; do mv "$f" dest/; done
is needlessly complicated but safe, because if I accidentally specified the filedst
instead of the directorydest
(but kept the slash!), it would give me onemv: failed to access 'dst/': Not a directory
error per file. However, if I omitted the trailing/
, then it would rename each file todst
, replacing the previousdst
, and only the last file would remain.Similar bad outcomes can be achieved with
find
, including in situations where it may be reasonable to usefind
(but differently, and still with extra care). For example, suppose I wanted to move all files matching the globfile*.txt
in an entire directory tree (except indest
itself) into the directorydest
. I might first think to use this:Because I included a trailing
/
, writingdest/
instead ofdest
, this wouldn't overwrite a file calleddst
even if I wrotedst
instead ofdest
. But it has the related problem that it will overwrite files that it has already copied, if files in different parts of the directory tree have the same name. For example, if there's ana/file01.txt
and ab/file01.txt
, one will overwrite the other. To avoid that, too, it's better to use something like this:The other benefit of
-t dir
is that, because it lets you specify the destination directory before the items being moved, it's compatible with the+
form of-exec
, where multiple items are passed to a command, thereby running fewer commands (often just one):In both cases (they're the same except for
\;
vs.+
) I've also passed the-i
option to prompt before each operation that would overwrite a file. If you just want to silently skip those, writen
instead ofi
. If you want to test yourfind
commands first, you can writeecho
after-exec
but before the rest of the command to print what would be run. For example:(Of course, that's in the original directory I showed, where all the files to moved are in the same location, and thus where
find
is overkill and the most complicated reasonable command to use ismv -it dest/ file*.txt
.)No, what you suggest should(!) not be possible. You probably need to look better at the destination. Use
history
to get a list of previous issued commands.A couple of things:
If there IS a move done ...
See
info coreutils 'mv invocation'
(on-line version https://www.gnu.org/software/coreutils/manual/html_node/mv-invocation.html#mv-invocation ) for how mv works and more specific this part:So a move consists of 2 parts:
cp -a
mv
The removal part of the move is done AFTER there is confirmation the copy has been done correctly.
if your mv consists of multiple files the copy and move are done in between. So a
will do a
so when there is a problem in between a and f it will have finished the move of a and up to where the problem appeared. This also applies to using wildcards.
Regarding the edit
This moves test.txt to / and renames it to ben. And
correctly errors out. Do a
and it will show the file.
What you always should do is append a / if you want to move a file to a directory.
would error out as /ben/ does not exists.