cp copies files and directories. It’s one of the first commands everyone learns, and a few options make the difference between a correct copy and a subtly broken one (lost permissions, overwritten files, copied symlinks).
cp [options] SOURCE DESTINATION
cp [options] SOURCE... DIRECTORY
Copy files
cp notes.txt notes-backup.txt # copy to a new name
cp notes.txt /tmp/ # copy into a directory (keeps the name)
cp a.txt b.txt c.txt /srv/archive/ # several files into a directory
cp /etc/nginx/nginx.conf{,.bak} # brace expansion: nginx.conf → nginx.conf.bak
The last form is a handy habit before editing any config file.
Copy directories
cp -r site/ /var/www/site-copy
-r (recursive) is required for directories. Watch the trailing slash and whether the destination exists:
- If
/var/www/site-copydoesn’t exist, it’s created as a copy ofsite. - If it exists,
siteis copied into it as/var/www/site-copy/site.
To copy the contents of a directory into an existing one:
cp -r site/. /var/www/site-copy/
Preserve permissions, ownership and timestamps
By default, cp creates new files owned by you, with default permissions and the current time. For backups and migrations you usually want an exact copy:
cp -a /var/www/site /backup/site
-a (archive) = -dR --preserve=all: recursive, preserves mode, ownership, timestamps, links and extended attributes, and copies symlinks as symlinks. Ownership is only preserved when running as root.
Preserve just some attributes:
cp -p file dest # mode, ownership, timestamps
cp --preserve=mode,timestamps file dest
Don’t overwrite by accident
cp -i file dest # ask before overwriting
cp -n file dest # never overwrite (no-clobber)
cp -u src/* dest/ # only copy when source is newer or dest is missing
cp --backup=numbered file dest # keep the old version as dest.~1~
Some distributions alias cp to cp -i for root; scripts should use explicit options.
Symbolic links
cp link dest # copies the file the link points to (default for files)
cp -P link dest # copy the link itself
cp -L -r dir dest # follow all links while copying recursively
With -r, symlinks inside directories are copied as links by default on GNU cp; -a also keeps them as links.
Verbose and progress
cp -av /var/www/site /backup/ # print each file
cp has no progress bar. For large copies use rsync --info=progress2 or pv for single files:
pv bigfile.iso > /mnt/usb/bigfile.iso
Sparse files and reflinks
cp --sparse=always disk.img copy.img # keep holes in sparse files (VM images)
cp --reflink=auto big.db big-copy.db # instant copy-on-write clone on Btrfs/XFS (falls back to normal copy)
cp vs rsync
Use cp for local, one-off copies. Use rsync when:
- copying to another server,
- re-running the same copy (only changes are transferred),
- you need progress, resume, exclusions or a dry run.
cp -a and rsync -a produce equivalent results locally; rsync is simply better at repeated and remote jobs.
Common mistakes
cp -r dir destwhendestexists — ends up asdest/dir.- Forgetting
-awhen copying a web root as root — files become owned by root, and the web server can’t write uploads. Fix with chown. - Copying a running database’s files — use the database’s dump tools instead. See mysqldump.
Quick reference
| Task | Command |
|---|---|
| Copy file | cp src dest |
| Copy directory | cp -r src dest |
| Exact copy (backup) | cp -a src dest |
| Ask before overwrite | cp -i |
| Never overwrite | cp -n |
| Only newer files | cp -u |
| Copy contents of dir | cp -r src/. dest/ |