Copy directory contents using 'cp' command

35

15

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?

nomount

Posted 2009-08-20T17:06:40.087

Reputation:

Great answer to this question here on AskUbuntu: https://askubuntu.com/a/86891/401660

– Josh Habdas – 2019-12-19T11:43:07.460

Answers

32

Try:

cp -ra /backup/olduser/. /home/newuser

user4358

Posted 2009-08-20T17:06:40.087

Reputation:

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 – 2019-10-23T08:33:35.363

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 – 2011-08-24T02:33:20.393

This worked for me but cp -r ./a b didn't. Any idea why? – Brig – 2012-02-21T19:07:34.400

3works for me too, but the r option is not needed. The a option implies r. – MountainX – 2012-04-14T17:38:07.453

1the -r parameter seems to be a bit redundant at this point! – Master of Celebration – 2013-09-12T13:56:20.327

23

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.

Rich Bradshaw

Posted 2009-08-20T17:06:40.087

Reputation: 6 324

Don't you want -a to get all files? – b w – 2009-08-20T17:22:17.403

7The -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 – 2009-08-21T03:26:22.947

Yep, the version I'm using looks like this:

'cp [-R [-H | -L | -P]] [-fi | -n] [-pvX]' with no -a option. – Rich Bradshaw – 2009-08-21T09:01:15.017

2Easy way: cp -R /some/dir/* /another/dir – n0pe – 2011-07-04T20:51:06.910

1This copies a/foo to b/a/foo instead of to b/foo – Sparr – 2012-07-30T15:48:53.017

What about hidden . files? – mch – 2009-11-07T21:52:38.197

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 – 2009-11-08T00:33:11.033

-a Archive mode. Same as -RpP. – briealeida – 2009-11-14T07:56:33.663

19

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.

Nicolas Bonnefon

Posted 2009-08-20T17:06:40.087

Reputation: 321

@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 – 2014-06-20T10:57:43.730

@quuxman thank you, I wasn't aware of it back then. I'm gonna remove my old comment to avoid confusing people. – Timo Huovinen – 2014-06-20T19:35:34.447

How does the /. work? – bradley.ayers – 2011-08-24T02:54:38.750

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 – 2011-10-20T11:19:13.410

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 – 2013-06-01T16:46:51.870

6

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.

Peter Eisentraut

Posted 2009-08-20T17:06:40.087

Reputation: 6 330

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 – 2014-06-20T10:59:40.420

1i 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 – 2009-11-08T00:37:31.750

2

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.

mch

Posted 2009-08-20T17:06:40.087

Reputation: 121

1But this still excludes names that *begin with* .. (e.g., ... or ..super-hidden). – Scott – 2014-07-21T16:12:09.590

0

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

cp -rf * ^.* 

Seeeve

Posted 2009-08-20T17:06:40.087

Reputation: 9

0

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/

gaqzi

Posted 2009-08-20T17:06:40.087

Reputation: 1 058

@mch: But .[^.]* still excludes names that *begin with* .. (e.g., ... or ..super-hidden). – Scott – 2014-07-21T16:13:11.590

Usually * does not match . or .., but it does if you use .*. Try echo .*. You can exclude . and .. with the following pattern: .[^.]*. – mch – 2009-11-07T21:52:04.547