126

I am migrating my home directory from an old system to a new one, and the tarball I made contains everything, including hidden files like .bashrc. However, when I move the contents of the unpacked tarball (which are in /tmp) to my new home directory, the hidden files do not copy (mv /tmp/home/rcook/* /home/rcook/). How can I get mv to move them?

Actually, I think the problem is not with mv, but with bash's globbing. If I do this:

mkdir a
mkdir b
touch a/.foo
touch a/bar
mv a/* b/
ls -a a/ b/

I see this:

a/:
.  ..  .foo

b/:
.  ..  bar

a/.foo did not move. So how can I get the * wildcard to find hidden files?

Yes, I suppose I could decompress the tarball directly into my home directory, but the tarball decompresses into home/rcook/..., and I want to be sure I overwrite the new .bashrc, etc. with the old, customized versions, and knowing how to find and move hidden files is a worthwhile skill. Suggestions?


Some answers suggest doing something like mv src/.* dest/. However, I tried this on my test directories and got errors. Starting with:

rcook$ ls -a a/ b/
a/:
.  ..  bar  .foo

b/:
.  ..
rcook$ mv a/.* b/
mv: cannot move 'a/.' to 'b/.': Device or resource busy
mv: cannot remove 'a/..': Is a directory
rcook$ ls -a a/ b/
a/:
.  ..  bar

b/:
.  ..  .foo

What am I doing wrong?

140

You can do this :

shopt -s dotglob
mv /tmp/home/rcook/* /home/rcook/

You can put

shopt -s dotglob

in your ~/.bashrc if you want it to be the default.

See http://mywiki.wooledge.org/glob


Another approach to copy the dot files:

mv /tmp/home/rcook/.[!.]* /home/rcook/

Don't use the pattern ..* as it matches .. (pointer to the parent directory). If there are files whose name begin with two dots (..something), also use the pattern ..?*.

  • Please check out the additions I put at the bottom of my question. Thanks. – Randall Cook Feb 21 '13 at 19:25
  • 1
    Nothings wrong, . and .. are specials dirs : respectively current dir & parent dir. It's just a warning. Better use shopt -s dotglob solution – Gilles Quenot Feb 21 '13 at 19:27
  • I ended up just doing two moves: mv home/rcook/* /home/rcook/ followed by mv home/rcook/.* /home/rcook/. This did the trick, though I wish I had followed the link and read about dotglob mode first. It would have saved me a step. +1 – Randall Cook Feb 22 '13 at 4:19
  • So the second approach requires the use of absolute paths? – franzlorenzon Oct 31 '13 at 14:24
  • 3
    If you're using zsh, you can use the D globbing qualifier or the GLOB_DOTS shell option. – mgalgs Dec 23 '14 at 23:39
41

In your additions, you got errors but the code still worked. The only thing to add is that you told it only to copy the dot files. Try:

mv src/* src/.* dst/

You will still get the errors for the . and .. entries, which is fine. But the move should succeed.

~/scratch [andrew] $ mv from/* from/.* to/
mv: cannot move ‘from/.’ to ‘to/.’: Device or resource busy
mv: cannot remove ‘from/..’: Is a directory
~/scratch [andrew] $ ls -a from/ to/
from/:
.  ..

to/:
.  ..  test  .test
  • 1
    Good points, @AndrewSchwartz. I like this approach, too. I think it deserves more recognition. – Randall Cook Jul 28 '15 at 5:00
  • I like @Drake Clarris answer a little more, because I'm running on Amazon AWS CodeBuild and the non zero return code actually caused my build to stop. I ended up moving the one .hidden file I had explicitly to solve my problem though. – HeyWatchThis May 27 at 22:58
  • If the non-zero exit code is a problem you could suppress it, e.g. by appending || : (|| means execute the following on false/error, : is noop command). But that would suppress legit errors too, e.g. destination folder does not exist. I can't find a more elegant way using mv to exclude the . and .. entries. Butt big plus for me over cp is not writing new files to disk. – Andrew Schwartz May 29 at 13:30
10

If you ls -l in a directory, you will see . and .. among listed files. So, I think mv .* /dest takes those pointers into account. Try:

mv /tmp/home/rcook/{*,.[^.]*,..?*} /home/rcook/

this will ignore those current and parent dir pointers.

You will get an error if any of the three patterns *, [^.]* or ..?* matches no file, so you should only include the ones that match.

7

Two possible solutions I can think of. The first is to use cp instead with its recursive option, copying the current directory to the destination.

cp -Rp . /desired/directory

then you can remove the source files in the current directory

Alternatively, if you know the files are sanely named (no spaces, wildcards, non-printable characters), you can do something like this

mv $(ls -A) /desired/directory
  • 4
    Copy-then-remove is very different from move if the source and target are on the same filesystem. At least include the option -p to preserve metadata. Using ls should be a last resort, and here there are better, simpler ways. – Gilles Jun 14 '14 at 13:04
2

There isn't really such a thing as "hidden" files on Linux. Files which begin with a dot are just hidden from file listings by default.

To copy files even with a glob, you need to prefix the file with . such as mv -u .* foo and then .foo will appearn as foo/.foo when moved.

The -u option will only move the files when the source is newer, or the destination is missing. Or you could just ignore the errors about moving . and .. as they are special files and cannot be moved, but do get caught in the .* glob by the shell.

  • Please check out the additions I put at the bottom of my question. Thanks. – Randall Cook Feb 21 '13 at 19:25
0

So we have:

a
|-- .foo
`-- bar

and:

b

I took a huge time finding better solution than all the answers here.

Then I took 30 seconds for this command:

$ mv --help

Then I found my love:

$ mv a/ b/ -T

Note: I don't even understand the argument -T. It just did what I needed. Here it says:

-T, --no-target-directory treat DEST as a normal file

  • 1
    If you omit the slashes, you shouldn't need -T. Either way this is essentially telling mv to move the directory itself, rather than moving all the files from inside it. – thomasrutter Jul 28 '15 at 1:52
  • @thomasrutter, isn't moving the directory itself the same thing as renaming it? – Randall Cook Jul 28 '15 at 4:52
  • 3
    Yes, if the parent destination remains the same, it's essentially just renaming it. However you refer to it, it probably doesn't help answer the original question, which was about moving the files inside the directory into a given location. – thomasrutter Jul 29 '15 at 0:17
-1

If you want to copy files including hidden files to the current directory that you are in.

cp -Rp source-directory/. .
  • 1
    This is very similar to Drake Clarris's answer from 2013. Do you have anything else to add? – Randall Cook Sep 6 '16 at 5:02

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.