Copying a directory in Linux is easy; copying it to the right shape is where mistakes happen. The destination may end up with an unexpected nested folder, hidden files may be skipped by a wildcard, or metadata may not be preserved the way a backup requires.
Here’s how to pick the right command and check what it will do.
Start with cp -r
For a basic copy of a directory and its contents, use recursive mode:
cp -r project project-copy
Without -r (or -R), cp won’t copy a directory tree. On Linux’s GNU cp, -r and -R both mean recursive copying.
The destination’s current state changes the result:
- If
project-copydoes not exist, it is created as a copy ofproject. - If
project-copyalready exists as a directory, the result isproject-copy/project/.
That second behavior can be surprising if you rerun a command: the first run creates the destination, and the next run copies the source inside it. Check the target before copying when the directory layout matters:
ls project-copy
cp -r copies hidden files when you give it the directory itself. Hidden-file trouble usually comes from using a shell wildcard instead.
Copy the contents, including dotfiles
Suppose deploy/ already exists and you want the contents of build/ copied directly into it—not a new deploy/build/ directory. Use /. at the end of the source:
cp -r build/. deploy/
The . means “the contents of this directory,” including files whose names start with a dot, such as .env or .gitignore.
By contrast:
cp -r build/* deploy/
The shell expands * before cp runs. By default, that pattern does not match dotfiles, so those files are left out. If you need a complete copy, prefer build/. over build/*.
When metadata and symlinks matter, use cp -a
A recursive copy is usually enough for a working copy, but it is not the best choice when you need to preserve the source tree’s attributes. For backups, migrations, or directories containing symlinks, use archive mode:
cp -a project project-backup
GNU cp -a is equivalent to recursive copying with preservation of attributes and symlink handling. It preserves attributes it can, including permissions, ownership, timestamps, and extended attributes where supported. It also copies symlinks as links rather than following them to copy their targets.
Preserving ownership may depend on your privileges, and filesystem support affects which attributes can be retained. For a regular working copy where exact metadata is unimportant, cp -r is simpler. For a faithful local copy, cp -a is usually the better fit.
Use rsync for repeat copies or large trees
If you’ll copy the same directory repeatedly, or a large transfer may need to be resumed, rsync is often more useful than starting over with cp. It can transfer changes since a previous run and report progress:
rsync -av --progress project/ project-copy/
The trailing slash on project/ means to copy its contents into project-copy/. Without that slash, the source directory itself is included in the destination path. That small syntax difference is worth checking before running a sync. For more patterns and transfer examples, see this practical rsync command guide.
For a one-off copy to another machine, cp only works with paths on the local system. Use a network transfer tool such as scp -r or rsync over SSH instead. If you choose SCP, review the directory-copy syntax and its destination behavior.
A quick decision guide
-
Simple local directory copy:
cp -r source destination -
Copy contents into an existing directory, including hidden files:
cp -r source/. destination/ -
Preserve metadata and symlinks where possible:
cp -a source destination -
Repeat or transfer a large copy:
rsync
Before you run the command, ask two questions: does the destination already exist, and do I need the directory itself or only its contents? Answering those usually prevents the most common copy surprises.
I originally published a more detailed version of this guide on the SSHFlow blog.
I'm also building SSHFlow — an SSH client where every server gets its own workspace for terminals, SFTP, code, and databases.
Top comments (0)