cp is one of those commands used every day but known at best to a third of its capability. Copying a single file is one line. But copying an entire directory while preserving permissions, timestamps, and symbolic links — skipping files that are already up to date — that is a different story. Here is the full picture.
Basic Usage
Copy a file to another directory:
cp file.txt /path/to/folder/
Copy and rename at the same time:
cp file.txt /path/to/folder/newname.txt
Copy several files to one directory:
cp file1.txt file2.txt file3.txt /path/to/folder/
Copy all files with a specific extension:
cp *.log /var/backup/logs/
Copying Directories: the -r Flag
Without -r, attempting to copy a directory gives the error omitting directory. Recursive copying requires the -r or -R flag:
cp -r /var/www/mysite /var/backup/mysite
One important detail: if the target directory already exists, the source folder is copied inside it. If the target does not exist, it is created with the desired name. This causes confusion on repeated runs.
Preserve Permissions, Owner, and Timestamps: the -p Flag
Plain cp creates a new file with the current date and permissions inherited from umask. For backups this is unacceptable — original metadata must be kept.
The -p flag preserves: permissions, owner, group, timestamps:
cp -p config.conf /backup/config.conf
For directories — combined with -r:
cp -rp /etc/nginx /backup/nginx
Do Not Overwrite Existing Files: Flags -n and -i
Copy only if the file does not exist at the destination:
cp -n source.txt /target/
-n (no-clobber) silently skips a file if it already exists. Essential when filling a directory without risking overwriting current versions.
The -i flag asks for confirmation instead of silently skipping:
cp -i file.txt /target/
Copy Only Newer Files: the -u Flag
-u (update) copies a file only if the source is newer than the existing file at the destination, or if the destination does not have it at all:
cp -u /var/www/html/*.php /backup/html/
This is a rough synchronization equivalent — useful for regular backups of changed files.
See What Is Happening: the -v Flag
By default cp works silently. The -v flag (verbose) prints each copied file:
cp -rv /etc/nginx /backup/nginx
When copying thousands of files this floods the terminal — better to redirect to a log:
cp -rv /var/www/html /backup/html > /tmp/cp_log.txt 2>&1
Force Replace: the -f Flag
If the destination file is write-protected, plain cp stops with an error. The -f flag (force) deletes the existing file first, then copies:
cp -f source.conf /etc/app/config.conf
Use carefully on production servers — -f does not ask for confirmation.
Preserve Symbolic Links: the -d Flag
By default cp -r follows symbolic links and copies the actual content. To copy the link itself:
cp -d symlink /target/
Most often needed when copying /etc/nginx/sites-enabled/ where active configs are symlinks pointing to sites-available.
Flag Combinations for Common Tasks
Backup a directory with all metadata and progress output:
cp -rpv /var/www/mysite /backup/mysite_$(date +%Y%m%d)
Sync a directory, copying only what changed:
cp -ru /var/www/html /backup/html
Quick config backup before editing:
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
When cp Is Not Enough: rsync
For serious synchronization and backups, cp falls short compared to rsync. rsync can: copy only changed blocks (not whole files), show progress in percentages, work over SSH, and exclude files by pattern.
Basic rsync with preserved permissions and symlinks:
rsync -av /var/www/html/ /backup/html/
The trailing slash after the source matters — without it rsync copies the folder inside the target; with it, only the contents.
Quick Reference
| Task | Command |
|---|---|
| Copy a file | cp file.txt /target/ |
| Copy and rename | cp file.txt /target/newname.txt |
| Copy a directory | cp -r /source/ /target/ |
| Preserve permissions and timestamps | cp -p file.txt /target/ |
| Directory with metadata | cp -rp /source/ /target/ |
| Do not overwrite | cp -n file.txt /target/ |
| Ask before overwriting | cp -i file.txt /target/ |
| Only newer files | cp -u /source/*.php /target/ |
| With progress output | cp -rv /source/ /target/ |
| Force replace | cp -f file.txt /target/ |
| Copy symlink itself | cp -d symlink /target/ |
| Backup with date stamp | cp -rp /source/ /backup/source_$(date +%Y%m%d) |