Skip to main content

Linux command: cp

08 July 2026

Copying a file feels like the most ordinary thing you can do on a computer. You type cp, the old file, the new name, and press Enter. Done. But that quiet little command hides some of the sharpest edges in Linux: it can silently overwrite your work, it treats copying a directory as a special case you have to ask for, and on a modern filesystem it can copy a 10 GB file in a fraction of a second without using any extra disk space. Learning cp properly is learning how Linux thinks about files.

1. The Basics

The job of cp is to copy a file: it reads the bytes of a source and writes an independent duplicate at a destination. The original stays exactly where it was, untouched. Afterwards you have two separate files that happen to hold the same content but live their own lives; change one and the other does not move.

That independence is the whole point, and it is what separates cp from its cousin mv. When you move a file within the same filesystem, nothing is copied at all; only its name changes. When you copy a file, the data is genuinely read and written again, so a copy of a large file takes real time and real space. Keep that difference in mind; it explains almost everything cp does.

The command reads left to right: the last argument is the destination, and everything before it is a source.

$ cp report.txt report-backup.txt

The command everyone learns on day one. Behind those two letters sits a surprising amount of care about what "a copy" really means: permissions, timestamps, symbolic links, directories, and whether the old file at the destination survives.

This article starts with the simplest possible copy and builds up to copying whole directory trees, preserving metadata, making backups instead of overwriting, and the copy-on-write trick that makes huge copies feel instant. By the end you will know not only how to copy a file, but exactly when cp is about to destroy one.

The right mental model: cp makes a second, independent file. The original is safe; the danger is always at the destination, because by default cp overwrites whatever is already there without a word.

Back to top

2. Where the Name Comes From

The name cp is simply short for copy. There is no hidden meaning this time; the two letters are the first two consonants of the word.

cp  =  CoPy

Like most early Unix commands, the name was cut down to the bare minimum on purpose. Early Unix was typed on slow teletype terminals that printed every character onto paper, so short names saved both typing time and ink. That is why the command is cp and not copy. The same instinct gave us mv (move), rm (remove), and ls (list): a whole vocabulary of two-letter verbs.

If you ever move to Windows, note that its shell uses the fuller word copy instead. The Unix habit of terse names is a historical fingerprint, not a rule of nature.

Back to top

3. A Short History

The cp command is one of the original Unix tools. It shipped in Unix 1st Edition at Bell Labs in 1971, alongside cat, mv, and rm, and it has been present on every Unix-like system since: Linux, macOS, the BSDs, Solaris, and AIX. The core idea, "read a file and write it out under a new name", has not changed in over fifty years.

What has changed is what happens underneath. For decades cp was a plain loop that read a block of bytes and wrote it back out. Modern versions are far cleverer: they can ask the kernel to copy data without dragging it through the program, detect long runs of zero bytes and skip them (sparse files), and on some filesystems share data blocks between the source and copy until one of them changes.

EraMilestone
1971 cp ships in Unix 1st Edition at Bell Labs
1980s BSD and System V add recursive copying and metadata preservation
1990s GNU coreutils cp becomes the standard version on Linux
2011 GNU cp gains --reflink for copy-on-write clones (Btrfs, later XFS)
2021 coreutils 9.0 uses reflink copies automatically when the filesystem supports it

There are two families you will meet in practice. Most Linux systems run the GNU coreutils version of cp. macOS and the BSDs ship the BSD version. They agree on the everyday flags such as -r, -i, -p, and -f. The differences are in the extras: GNU adds long options (for example --preserve, --parents, and --reflink) that BSD either spells differently or lacks. This article uses the GNU version, which is what you will find on almost every Linux server.

Back to top

4. Simple Use Cases

4.1 The Simplest Possible Copy

Give cp a source and a destination name, and it makes a copy under that name. In the examples below, the line that starts with $ is what you type; a command that prints nothing simply succeeded, which is the normal Unix way of saying "all good".

$ cp notes.txt notes-copy.txt
$ ls
notes.txt  notes-copy.txt

You now have two independent files. Editing notes-copy.txt leaves notes.txt exactly as it was.

4.2 Copying Into a Directory

If the destination is an existing directory, cp puts the copy inside it and keeps the original filename. This is the most common everyday use: dropping a file into a folder.

$ cp report.txt /home/peter/backups/
$ ls /home/peter/backups/
report.txt

The trailing slash on backups/ is a good habit: it makes your intent clear and, if you mistype the folder name, cp fails loudly instead of quietly creating a file called backups.

4.3 Copying Several Files at Once

When you give more than two arguments, cp treats the last one as a destination directory and copies every file before it into that directory. This is where the "last argument is the destination" rule really matters.

$ cp index.html style.css script.js /var/www/site/

All three files land in /var/www/site/. If that last argument is not an existing directory, cp refuses and prints an error, which is a helpful safety net.

4.4 Copying a Whole Directory: -r

By default cp refuses to copy a directory. This surprises newcomers, but it is deliberate: copying a folder means copying everything inside it, possibly thousands of files, so cp makes you ask for it on purpose. The -r flag (short for recursive) grants permission to descend into the directory and copy its whole tree.

$ cp project project-backup
cp: -r not specified; omitting directory 'project'

$ cp -r project project-backup
$ ls
project  project-backup

The name "recursive" describes the mechanism: cp enters the directory, copies each file, and whenever it meets another directory it repeats the same steps inside that one, all the way down. You will also see -R; for everyday use the two are the same, and both differ only in rare edge cases involving special files.

Copying a single file is the easy half. The moment a directory is involved, cp changes character: it needs -r, and whether the destination already exists quietly changes where your files end up. Section 6 returns to that trap.

Back to top

5. Moderate Use Cases

5.1 Not Overwriting Silently: -i and -n

By default cp overwrites an existing destination file without warning. If report-backup.txt already holds something important, a careless copy wipes it out. Two flags make cp more careful.

The -i flag (short for interactive) asks before it overwrites, so you can stop a mistake:

$ cp -i new.txt report-backup.txt
cp: overwrite 'report-backup.txt'? n

The -n flag (short for no-clobber) is the quiet version: it skips any file that already exists and never asks, which is handy in scripts where you only want to fill in missing files.

$ cp -n new.txt report-backup.txt      # existing file is left untouched

5.2 Seeing What Happens: -v

The -v flag (short for verbose) prints one line per file copied. On a big recursive copy this turns a silent, worrying pause into a visible list of progress.

$ cp -rv photos /backup/
'photos/2023' -> '/backup/photos/2023'
'photos/2023/beach.jpg' -> '/backup/photos/2023/beach.jpg'
'photos/2024/city.jpg' -> '/backup/photos/2024/city.jpg'

5.3 Keeping the Metadata: -p

A plain copy is a new file. It gets a fresh modification time (now) and takes its permissions from your current settings, not from the original. Most of the time that is fine. For backups and system files it is not: you often want the copy to keep the original's permissions, ownership, and timestamps. The -p flag (short for preserve) does exactly that.

$ cp file.conf copy.conf          # copy has a new timestamp and default mode
$ cp -p file.conf copy-kept.conf  # copy keeps mode, owner, and times

You can ask for more or less with the long form --preserve=, choosing from mode, ownership, timestamps, links, and all:

$ cp --preserve=timestamps a.log b.log   # keep only the times

5.4 The Archive Shortcut: -a

When you copy a directory tree that contains symbolic links, special permissions, and files you want left exactly as they are, typing out every preserve option is tedious. The -a flag (short for archive) bundles the right defaults together: it is the same as -dR --preserve=all. It copies recursively, keeps every attribute, and does not turn symbolic links into real files.

$ cp -a /etc/nginx /root/nginx-backup   # a faithful, complete copy

"Every attribute" means more than mode, owner, and timestamps. --preserve=all (and therefore -a) also tries to keep extended attributes (xattr), ACLs, and the SELinux security context, where the destination filesystem supports them. That coverage is why cp -a is the closest cp comes to "make an exact duplicate of this tree", and why it is the right choice for backing up a folder as-is.

It has a limit, though. cp preserves what the local filesystem understands; copying to a filesystem or another machine that handles permissions differently can quietly drop some of that metadata. For faithful copies between Linux systems, many administrators still reach for rsync (with -a) or tar, which section 7 revisits.

Back to top

6. Advanced Use Cases

6.1 The Directory Trap: Destination Exists or Not

This is the single most confusing thing about cp -r, and it catches everyone at least once. When you copy a directory, the result depends on whether the destination already exists.

$ cp -r src dst        # dst does NOT exist: dst becomes a copy of src
$ cp -r src dst        # dst DOES exist:     src is copied INSIDE dst
                       #                     giving dst/src

Run the same command twice and you get two different layouts. The first run creates dst as a copy of src. The second run, because dst now exists, places a copy of src inside it, producing dst/src. To copy only the contents of a directory into another, name the contents explicitly:

$ cp -r src/. dst/     # copy what is inside src into dst, no extra level

The src/. form means "the contents of src", which sidesteps the whole exists-or-not question. When a backup script mysteriously produces backup/backup/backup, this rule is almost always why.

6.2 Backups Instead of Overwrites: -b

Sometimes you want to overwrite a file but keep the old version just in case. The -b flag (short for backup) renames the existing destination out of the way before writing the new one, adding a ~ to its name by default.

$ cp -b new.conf app.conf
$ ls
app.conf  app.conf~          # the old app.conf is now app.conf~

With --backup=numbered you get app.conf.~1~, app.conf.~2~, and so on, so repeated copies never lose an earlier version. This is a lightweight safety habit for editing configuration files by hand.

6.3 Rebuilding Paths: --parents

The --parents option recreates the source's full directory path under the destination. It is invaluable when you want to copy scattered files while keeping their folder structure intact.

$ cp --parents src/config/app.ini /backup/
$ ls /backup/
src                          # the full src/config/ path is rebuilt
$ ls /backup/src/config/
app.ini

Instead of dumping app.ini straight into /backup/, cp rebuilds src/config/ underneath it. This keeps a set of copied files organised exactly as they were.

Two flags make cp create links rather than real duplicates, which saves space when you do not need a truly independent second copy.

FlagShort forWhat it makes
-l link A hard link: a second name for the very same data on disk
-s symbolic-link A symlink: a small pointer file that names the original path

A hard link (-l) is not a copy at all; it is another name for the same bytes, so it uses no extra space and editing through either name changes the one underlying file. A symbolic link (-s) is a tiny signpost that points at the original by its path, and it breaks if the original moves away. Neither is a backup, because there is still only one real copy of the data.

When a source is itself a symbolic link, cp has to decide: copy the link, or copy the file it points to? The -L flag (short for dereference) follows the link and copies the real file. The -P flag (short for no-dereference) copies the link itself, leaving a link in the destination. With -a you get -P behaviour, which is usually right for faithful backups.

Back to top

7. Something Most Users Do Not Know

Here is the genuinely surprising part. On a modern copy-on-write filesystem such as Btrfs or XFS, cp does not have to duplicate the data at all. With --reflink, it makes a copy that shares the same data blocks as the original. The two files look completely independent, but on disk they point at the same bytes until one of them is changed. Only then, and only for the blocks that actually change, is new data written. This is called copy-on-write.

$ cp --reflink=always huge.img huge-copy.img   # near-instant, uses ~0 extra space

Copying a 10 GB virtual machine image this way finishes in a fraction of a second and adds almost nothing to your disk usage. Since coreutils 9.0 (2021), GNU cp tries a reflink automatically (--reflink=auto) and quietly falls back to a normal copy on filesystems that cannot do it, so on the right filesystem you may already be getting this for free.

A reflink copy is not a link and not a snapshot: it is a real, separate file that happens to share storage until you edit it. It gives you the safety of a copy with the speed and space of a link.

7.2 cp Reads and Writes; mv Often Does Neither

People treat cp and mv as a matched pair, but underneath they are very different. Within a single filesystem, mv just changes a name in a directory; the data never moves, which is why moving a huge file is instant. cp always reads every byte of the source and writes it out again, so copying that same huge file takes real time and doubles the space used. The moment mv crosses to a different filesystem, though, it cannot simply rename, so it falls back to copying the data and then deleting the original, which is exactly what cp does plus an rm.

This is why a copy leaves the original in place and a move does not, and why an interrupted mv across disks can be more dangerous than an interrupted cp.

7.3 There Is No Undo, and the Source Is Not Always Safe

The famous danger of cp is at the destination: cp a b destroys whatever b was, with no confirmation and no trash can. There is no undo. But there is a subtler trap. Copying a file onto itself is caught and refused:

$ cp a a
cp: 'a' and 'a' are the same file

Yet the shell can hide that from cp. A glob like cp * backup.txt in a folder where backup.txt already matches * can feed the destination in as a source, and combined with other files the result is rarely what you meant. When you copy with wildcards, look closely at what the * actually expands to first.

7.4 Under the Hood: What "Copy" Really Costs

A traditional cp is a small loop: open() the source, open() (or create) the destination, then repeatedly read() a block of bytes and write() it out until end-of-file, and finally close() both. Modern cp improves on this in three ways worth knowing.

TechniqueWhat it does
Sparse detection (--sparse) Notices long runs of zero bytes and skips writing them, so a mostly-empty file (such as a VM disk image) copies small
copy_file_range() Asks the kernel to copy data directly, without pulling it through the program
Reflink (copy-on-write) Shares data blocks with the source until one file is changed

You do not have to request any of this by hand; GNU cp picks the fastest safe method for the filesystem you are on. Sparse handling defaults to --sparse=auto, but you can force it with --sparse=always or switch it off with --sparse=never. The lesson is that "copy this file" is not one fixed operation. What it costs in time and space depends on the filesystem beneath your feet.

7.5 Knowing Where cp Stops

Part of expertise is knowing when a different tool fits better. cp is perfect for a one-off, local copy. Beyond that, others take over.

NeedUseWhy
Sync folders, only changed parts rsync Copies just the differences and can resume; ideal for repeated backups
Copy to another machine scp / rsync Copies over the network with SSH
Move within a filesystem mv Renames instantly instead of duplicating data
Bundle a tree into one file tar Preserves the whole structure and metadata as a single archive
Clone a whole disk or partition dd Copies raw blocks, including the filesystem itself, not just the files inside it

Learn cp first anyway. It is on every machine you will ever log in to, including a rescue shell, and everything rsync and tar do is built on the same idea of reading a source and writing a faithful copy.

Back to top

8. Best Practices

  • Assume the destination will be overwritten. Before cp a b, ask what b holds now. There is no undo. Use -i when working by hand and you are unsure.
  • Use -a to back up a directory. It copies recursively and keeps permissions, timestamps, and symbolic links, which a plain cp -r can quietly change.
  • Watch the directory-exists trap. With cp -r src dst, the result differs depending on whether dst exists. Use src/. when you mean "the contents of src".
  • Add a trailing slash to a destination directory. cp file dir/ fails loudly if dir is missing, instead of silently creating a file named dir.
  • Prefer rsync for anything you repeat. For backups you run more than once, rsync copies only what changed and can resume after an interruption.
  • Reach for the manual without hesitation. The habit that separates beginners from professionals is typing man cp the moment a question comes up.
$ man cp                            # the full manual page
$ cp --help                         # a quick flag summary (GNU)
$ info coreutils 'cp invocation'    # the verbose GNU manual
Back to top

9. Common Mistakes

9.1 Three Common Myths

MythReality
"cp asks before overwriting." It does not. By default it overwrites silently. Add -i or -n for safety.
"cp -p keeps everything." Plain -p keeps mode, owner, and timestamps, but not symlinks-as-links. Use -a for a faithful tree.
"Copying a big file always needs big space." On Btrfs or XFS, a reflink copy shares blocks and uses almost none until you edit the copy.

9.2 Other Traps to Avoid

  • Overwriting without noticing. cp new important destroys important with no warning. There is no trash and no undo.
  • Forgetting -r for a directory. cp dir dst fails with "omitting directory". Add -r, and then mind the exists-or-not rule.
  • The double-nesting surprise. Running cp -r src dst a second time produces dst/src, not another dst. Use src/. to copy contents.
  • Losing permissions on system files. A plain copy of a config or script gets your default mode and a new timestamp. Use -p or -a when that matters.
  • Trusting a copy as a backup on the same disk. If the disk fails, both files go together. A real backup lives on separate storage.
Back to top

10. Summary

The cp command looks trivial, but it is a clean lesson in how Linux thinks about files, storage, and metadata.

  • cp is short for "copy". It reads a source and writes an independent duplicate; the original is safe, but the destination is overwritten without warning.
  • It dates back to Unix in 1971 and runs on every Unix-like system today, though what it does underneath has grown far cleverer.
  • The last argument is the destination. Copying into an existing directory keeps the filename; copying several files needs the last argument to be a directory.
  • Directories need -r (recursive). Whether the destination already exists changes where the files land; use src/. to copy contents.
  • -i asks before overwriting, -n skips existing files, -v shows progress, -b keeps a backup of the old file.
  • -p preserves mode, owner, and timestamps; -a is the archive shortcut for a faithful directory tree, including symbolic links.
  • -l makes a hard link and -s a symlink instead of a real copy; neither is a backup, because the data still exists only once.
  • On Btrfs or XFS, --reflink makes a copy-on-write copy that is near-instant and shares blocks until one file changes.
  • Know where cp stops: rsync for repeated or remote copies, mv to move within a filesystem, and tar to bundle a tree.
  • When in doubt, type man cp.

This is the quick reference worth keeping:

cp a b               copy file a to b (overwrites b silently)
cp a b c dir/        copy several files into a directory
cp -r dir dst        copy a directory tree
cp -r src/. dst/     copy the CONTENTS of src into dst
cp -i a b            ask before overwriting b
cp -n a b            skip b if it already exists
cp -p a b            keep mode, owner, and timestamps
cp -a dir dst        faithful copy: recursive, all attributes, links kept
cp -b a b            back up the old b as b~ before overwriting
cp --parents s/f d/  rebuild the source path under d/
cp --reflink=auto a b  copy-on-write copy where the filesystem allows

Small commands like cp hide a surprising amount of how Linux is built, and a single careless copy can undo hours of work. If your servers matter and you want them backed up and maintained by someone who understands what is really happening underneath, that is exactly the kind of work I enjoy helping with.

Back to top
Linux command: cp
Peter Martin
Peter Martin
Joomla Specialist

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.