I finally put together a summary of the different cases that come up when using cp to copy directories. A directory is also a special kind of file, but there are still a few easy points of confusion when copying one, especially the trailing / on the source path, the wildcard *, and whether the target directory already exists.
Below, [^] represents a space. Assume the /a directory contains files or subdirectories named 1, 2, and 3.
Table of Contents
cp[^]-R[^]/a/*[^]/b
Equivalent to:
cp -R /a/* /b/
This copies the contents under /a that match * into the /b directory. In other words, it copies each file and subdirectory inside /a, not the /a directory itself.
Two points are worth noting:
*is expanded by the shell and, by default, does not match hidden files such as.gitignore,.env,.config, and so on.- If there are subdirectories under
/a, recursive copying requires-Ror-r. In modern GNU coreutils,-Rand-rare usually equivalent; if portability matters, prefer the POSIX-specified-R.
If you also want to copy hidden files, consider using:
cp -R /a/. /b/
Here, /a/. means copying the contents of /a into /b, including regular files, hidden files, and subdirectories.
cp[^]-R[^]/a[^]/b/c
This form needs to be discussed in two cases: whether the target path /b/c already exists.
If /b/c does not exist
The command creates /b/c and copies all files and subdirectories from /a into /b/c. The effect is equivalent to cloning /a as a new directory named /b/c.
cp -R /a /b/c
The copied structure will look like this:
/b/c/1
/b/c/2
/b/c/3
If /b/c already exists
The command copies the /a directory itself into /b/c. After a successful copy, the directory structure is:
/b/c/a/1
/b/c/a/2
/b/c/a/3
That is, when the target directory already exists, the result of cp -R /a /b/c is not that the contents of /a are laid flat inside /b/c; instead, another a directory is created under /b/c.
cp[^]-R[^]/a/[^]/b
In common GNU/Linux implementations of cp, a trailing / on the source path usually does not change the main behavior when copying a directory. That is:
cp -R /a/ /b
Usually has a similar effect to this command:
cp -R /a /b
If /b already exists, the result is generally:
/b/a/1
/b/a/2
/b/a/3
Only if -R or -r is omitted will you see an error like this:
cp: omitting directory '/a/'
cp[^]-R[^]/a/[^]/b/
A trailing / on the target path indicates that the target should be a directory. Therefore:
cp -R /a/ /b/
When /b already exists, this usually copies the /a directory under /b, producing:
/b/a/1
/b/a/2
/b/a/3
If /b does not exist, the error message may vary slightly across systems and versions. Before using it in practice, you can verify the behavior on your own machine with the following commands:
mkdir -p /tmp/cp-test/a
printf 'onen' > /tmp/cp-test/a/1
printf 'twon' > /tmp/cp-test/a/2
printf 'threen' > /tmp/cp-test/a/3
mkdir -p /tmp/cp-test/b
cp -R /tmp/cp-test/a/ /tmp/cp-test/b/
find /tmp/cp-test -maxdepth 3 -type f | sort
Summary
The common conclusions are as follows:
cp -R /a/* /b/
Copies the contents inside /a that are matched by * into /b, excluding hidden files by default.
cp -R /a/. /b/
Copies all contents inside /a into /b, including hidden files.
cp -R /a /b/c
If /b/c does not exist, clones /a as /b/c; if /b/c already exists, copies /a as /b/c/a.
cp -R /a/ /b/
In common GNU/Linux environments, the trailing / on the source path usually does not make cp copy only the directory contents; to copy the contents of a directory rather than the directory itself, the clearer form is cp -R /a/. /b/.
