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-copy doesn’t exist, it’s created as a copy of site.
  • If it exists, site is 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.

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
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 dest when dest exists — ends up as dest/dir.
  • Forgetting -a when 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/

Related: mv, rm and tar.

  • Linux
  • Command Line
  • Basics