How do you copy all the contents of one directory into another?

For example:

$ cd /home/newuser
$ cp -a /backup/olduser/* .

The problem with the above is that the globing pattern '*' matches the hidden directories '.' and '..' and you end up with a directory 'olduser' inside 'newuser', as well as the contents.

You could also do something like this:

$ rmdir /home/newuser
$ cp -a /backup/olduser /home/newuser

But what if newuser already contains some default files and directories?

What is the simplest, most correct, easiest to remember and not mess-up way to move the contents of one directory to another using just the basic 'cp' command and the shell?



cp -ra /backup/olduser/. /home/newuser
| improve this answer | |
  • This is great, but I can't figure out exactly how it works. I think it's probably because I don't understand how . and .. work. Care to explain? – bradley.ayers Aug 24 '11 at 2:33
  • This worked for me but cp -r ./a b didn't. Any idea why? – Brig Feb 21 '12 at 19:07
  • 3
    works for me too, but the r option is not needed. The a option implies r. – MountainX Apr 14 '12 at 17:38
  • 1
    the -r parameter seems to be a bit redundant at this point! – Master of Celebration Sep 12 '13 at 13:56
  • The -a parameter does nothing to help in this situation. The command cp -r ./a/. b will copy the contents, and only the contents, of directory a into directory b. The -a flag preserves links, timestamps etc., which is not relevant to the question. – Steen Schütt Oct 23 '19 at 8:33

Two directories a and b.

Both have files in.

You are in a directory that contains a and b.

cp -r ./a b

-r = recursively.

| improve this answer | |
  • Don't you want -a to get all files? – b w Aug 20 '09 at 17:22
  • 7
    The -a argument is nothing do to with all files, it's short for archive, it will preserve file ownership, permissions, access times etc. The -a argument (while highly useful) isn't a standard option, and several cp implementations don't provide it. – theotherreceive Aug 21 '09 at 3:26
  • 1
    @mch: automatically included, because you've told cp to copy a directory a, and a/.somedotfile is contained by a. if b exists, this command will create an exact copy of a at b/a. – quack quixote Nov 8 '09 at 0:33
  • 2
    Easy way: cp -R /some/dir/* /another/dir – n0pe Jul 4 '11 at 20:51
  • 1
    This copies a/foo to b/a/foo instead of to b/foo – Sparr Jul 30 '12 at 15:48

Remember that, by default, cp copies the first directory into the second directory if the second exists.

For example cp -r a b will copy the directory a into b. If b does not exist, it will be created with the contents of a.

If you want to copy the content of a into b (for example when copying a whole filesystem into a mount point) use:

cp -r a/. b

as in the previous answer.

Please also note that -a, used in some of the other answers, is the same as -dr --preserve=all and will preserve timestamps, context and extended attributes.

| improve this answer | |
  • How does the /. work? – bradley.ayers Aug 24 '11 at 2:54
  • a/. represents the content of directory 'a' as opposed to the directory itself, in most situation it is synonymous but when using cp -r, it avoids cp default behaviour (copying a INTO b). – Nicolas Bonnefon Oct 20 '11 at 11:19
  • awesome tip, this is exactly what I was looking for but failed to find elsewhere - all that 'foo/*' or '-r foo/' that fails in corner cases. – Tener Jun 1 '13 at 16:46
  • @TimoHuovinen '.' is not a wildcard at all. It is literally the "parent" directory, and '..' is the grandparent. This means '/foo/./././././.' is the same directory as '/foo', and '/foo/bar/..' is the same directory as '/foo'. Think of them as hardlinks that are builtin to the filesystem. – quuxman Jun 20 '14 at 10:57
  • @quuxman thank you, I wasn't aware of it back then. I'm gonna remove my old comment to avoid confusing people. – Timo Huovinen Jun 20 '14 at 19:35

Unless you have seriously reconfigured your shell, the globbing pattern '*' does not match '.' or '..', as you can verify using just echo *. What it does instead do is omit files whose name begins with a '.', so your approach will miss all hidden files. You can tweak some of this behavior with shell options, for example the dotglob option in bash, but it then won't be the portable and robust option that you are looking for.

If you need to do this more than once or twice, I recommend that you look into rsync or unison (depending on specific needs) with carefully crafted source and target specifications.

Another alternative is to put the source directory in a tarball and untar it over the existing target directory.

| improve this answer | |
  • 1
    i use this: ( cd /src/dir ; tar cf - . ) | ( cd /dest/dir ; tar xf - ) ... the tar cf - . tar's the source directory, dotfiles included, and spits it to STDOUT, which gets piped to the STDIN of the tar xf -. – quack quixote Nov 8 '09 at 0:37
  • I think the whole point of the OP is how to reference files that start with '.' but not the special '.' and '..' directories. There is a far more elegant solution above instead of using rsync or some other complex program. – quuxman Jun 20 '14 at 10:59

This will copy both the normal and hidden files, while excluding the parent directory (..):

cd /directory/to/copy
cp -r * .[^.]* /destination/directory

If you do not exclude the parent directory, you end up with all of the contents of .. in your destination directory as well.

| improve this answer | |
  • 1
    But this still excludes names that begin with .. (e.g., ... or ..super-hidden). – Scott Jul 21 '14 at 16:12

To copy files that begins with a dot just do cp .* target/

So easiest is just to do the cp command two times.

As Peter Eisentraut sais normal globbing rules do not include .. and . (hm, how to end this sentence? ;)

Just use -r to make it recursive and -i to make cp ask whether you really want to overwrite a file.

cp -ri /backup/olduser/* /newuser/
cp -ri /backup/olduser/.* /newuser/
| improve this answer | |
  • Usually * does not match . or .., but it does if you use .*. Try echo .*. You can exclude . and .. with the following pattern: .[^.]*. – mch Nov 7 '09 at 21:52
  • @mch: But .[^.]* still excludes names that begin with .. (e.g., ... or ..super-hidden). – Scott Jul 21 '14 at 16:13

This works for copying all the files and directories except for hidden directories recursively from the current directory to wherever:

cp -rf * ^.* 
| improve this answer | |

Your Answer

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