Files and directories
cp
Copy files and directories, optionally keeping their timestamps, permissions and links.
cp [OPTION...] SOURCE... DEST
cp SOURCE DEST copies one file. With several sources, or when DEST is an existing
directory, the copies go into that directory under their own names. Directories need -r
(recursive).
A plain copy is a new file: owned by you, with a fresh modification time. -p keeps the mode,
owner (when allowed) and timestamps; -a (archive) does that recursively and also copies
symlinks as links, which makes it the right choice for backups.
cp overwrites existing files silently. -i asks first, -n never overwrites, and -u only
copies when the source is newer. For large or remote copies, or to sync a directory repeatedly,
rsync is more capable.
Examples
Copy a file
cp notes.txt notes-backup.txt
ls -l notes*
-rw-r--r-- 1 dev dev 190 Oct 31 20:19 notes-backup.txt -rw-rw-r-- 1 dev dev 190 Oct 25 05:30 notes.txt
The copy has the same size but a new modification time: plain cp does not preserve
timestamps.
Copy files into a directory
mkdir backup
cp todo.txt notes.txt backup/
ls backup
notes.txt todo.txt
With more than one source, the destination must be a directory; each file keeps its name. The trailing slash is optional but makes the intent clear and turns a typo into an error.
Copy a whole directory
cp -r src src-copy
find src-copy
src-copy src-copy/Makefile src-copy/util.sh src-copy/main.c src-copy/app.py src-copy/lib src-copy/lib/helpers.py
-r copies the directory tree. Because src-copy did not exist, it becomes the copy. Had
it existed, the result would be src-copy/src, a classic surprise.
Copying a directory without -r
cp logs logs-old
cp: -r not specified; omitting directory 'logs'
cp skips directories unless you ask for a recursive copy.
Keep the original timestamps
cp todo.txt plain.txt
cp -p todo.txt kept.txt
ls -l --time-style=+%F_%T todo.txt plain.txt kept.txt
-rw-rw-r-- 1 dev dev 62 2026-10-24_21:28:49 kept.txt -rw-r--r-- 1 dev dev 62 2026-10-31_20:19:31 plain.txt -rw-rw-r-- 1 dev dev 62 2026-10-24_21:28:49 todo.txt
plain.txt gets the current time; kept.txt keeps the original modification time (and
mode) because of -p.
Copy a tree exactly, links included
cp -a . ../demo-copy
ls -l ../demo-copy/link-to-notes
lrwxrwxrwx 1 dev dev 9 Oct 25 02:48 ../demo-copy/link-to-notes -> notes.txt
-a (archive) is -dR --preserve=all: recursive, timestamps and permissions kept, and
symbolic links copied as links rather than as the files they point to.
Never overwrite an existing file
Setup run before this example
echo "my local edits" > notes-copy.txtcp -n notes.txt notes-copy.txt
cat notes-copy.txt
my local edits
-n skips destinations that already exist, so the local edits survive. In coreutils 9.7 a
skipped file is not an error, so the exit status is 0.
Ask before overwriting
cp -i todo.txt notes.txt
head -1 notes.txt
cp: overwrite 'notes.txt'? Meeting notes, March
-i prompts when the target exists. The answer n (from standard input here) keeps
notes.txt as it was.
Keep a backup of the file being replaced
Setup run before this example
echo "new notes" > incoming.txtcp --backup=numbered incoming.txt notes.txt
cp --backup=numbered incoming.txt notes.txt
ls notes.txt*
notes.txt notes.txt.~1~ notes.txt.~2~
Instead of losing the old notes.txt, each overwrite renames it to notes.txt.~1~,
notes.txt.~2~ and so on. -b alone makes a single notes.txt~.
Copy only when the source is newer
Setup run before this example
mkdir out && cp -p data/*.csv out/
touch data/users.csvcp -uv data/*.csv out/
'data/users.csv' -> 'out/users.csv'
-u skips files whose destination is the same age or newer. Only users.csv was modified
since the last copy, so it is the only one copied (-v shows it).
Copy files and recreate their directory paths
mkdir bundle
cp --parents src/lib/helpers.py data/users.csv bundle/
find bundle -type f
bundle/src/lib/helpers.py bundle/data/users.csv
--parents keeps each source's relative path under the destination, handy for picking a few
files out of a tree.
Copy a symlink's target, not the link
cp link-to-notes copy1
cp -P link-to-notes copy2
ls -l copy1 copy2
-rw-r--r-- 1 dev dev 190 Oct 31 20:19 copy1 lrwxrwxrwx 1 dev dev 9 Oct 31 20:19 copy2 -> notes.txt
For a single file, cp follows the symlink and copies the content (copy1 is a regular
file). -P copies the link itself, so copy2 is a new link to notes.txt.
Common pitfalls
cp -r dir destbehaves differently depending on whetherdestexists: it createsdest, or copies intodest/dir. Usecp -r dir/. dest/to copy the contents into an existing directory either way.Forgetting the destination:
cp *.txtwith one match fails with "missing destination file operand", but with exactly two matches it silently overwrites the second file with the first. Always name the destination.Symlink handling depends on the options: without
-r, GNUcpfollows a symlink and copies the file; with-rit copies links as links. Say what you mean with-P(keep links),-L(copy targets) or-a.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
-ais supported by both, but GNU-only options include--parents,--backup,-t DIRand--reflink; macOS has its own-cfor copy-on-write clones.Trailing slash on the source matters on BSD/macOS:
cp -R src/ destcopies the contents ofsrc, while GNU copies the directory itself either way.cp -nexit status changed in GNU coreutils 9.x releases; do not rely on it to detect skipped files across versions.
Options worth knowing
A selection, described in our own words. For the full list, see cp(1) or cp --help.
| Option | What it does |
|---|---|
-r, --recursive | Copy directories recursively. |
-R | Same as -r. |
-a, --archive | Recursive, keep links, modes, owners and timestamps. |
-p | Keep mode, ownership and timestamps. |
-i, --interactive | Ask before overwriting. |
-n, --no-clobber | Never overwrite an existing file. |
-f, --force | Remove a destination that cannot be opened and try again. |
-u | Copy only when the source is newer or the destination is missing. |
--update[=UPDATE] | Choose which existing files to replace: all, none, none-fail or older. |
-v, --verbose | Print each file as it is copied. |
-l, --link | Make hard links instead of copies. |
-s, --symbolic-link | Make symbolic links instead of copies. |
-L, --dereference | Always follow symlinks in the sources. |
-P, --no-dereference | Copy symlinks as links. |
-t, --target-directory DIR | Copy all sources into DIR. |
-T, --no-target-directory | Treat DEST as a file name, never a directory. |
-b | Back up each existing destination file. |
--backup[=CONTROL] | Back up existing files: numbered, existing, simple or none. |
--parents | Recreate each source's path under the destination directory. |
--preserve[=ATTRS] | Keep the listed attributes: mode, ownership, timestamps, links, all. |
--reflink[=WHEN] | Make a copy-on-write clone where the filesystem supports it. |
--sparse WHEN | Control creation of sparse files: auto, always or never. |
-x, --one-file-system | Stay on the filesystem where each source starts. |
Related
mvMove or rename files and directories.rsyncCopy and synchronize files and directories, locally or over ssh, transferring only what changed.installCopy files into place and set their mode, owner and group in one step; can also create directories.lnMake links between files, symbolic (-s) or hard.scpCopy files between hosts over ssh, with cp-like syntax where a remote path is written HOST:PATH.- GlobbingHow *, ? and [...] match file names, what happens when nothing matches, and the shell options nullglob, failglob, dotglob, globstar and extglob.