Linux cp Command: Copy Files and Directories

Backing up a config file before editing it, duplicating a project directory, or putting a build artifact into place all start the same way, with a copy. cp is the command-line utility that handles this on Linux and Unix systems, and it is one of the most frequently used commands in the terminal.
To copy a file, run cp SOURCE DESTINATION. For example, cp file.txt /tmp/ copies file.txt into the /tmp directory. Directories need the -R option, as in cp -R project /tmp/.
This guide explains how to use the cp command with practical examples. For an overview of all tools available for copying files, see How to Copy Files and Directories in Linux
.
Syntax
The general syntax for the cp command is:
cp [OPTIONS] SOURCE... DESTINATIONSOURCE can be one or more files or directories. DESTINATION is a single file or directory. The behavior depends on what you pass:
- When
SOURCEandDESTINATIONare both file paths,cpcopies the source file to the destination. If the destination file does not exist, it is created. - When
SOURCEcontains multiple arguments,DESTINATIONmust be a directory. Each source file or directory is copied into it. - When
SOURCEis a directory, use the-Roption to copy it recursively.
To copy files and directories you must have at least read permission on the source and write permission on the destination directory. To learn more about file permissions, see Understanding Linux File Permissions .
Copy a File
To copy a file in the current working directory , specify the source file and the destination file name:
cp file.txt file_backup.txtBash brace expansion offers a shorter form for the same operation:
cp file.txt{,_backup}Both commands produce file_backup.txt as a copy of file.txt.
To copy a file to another directory, provide the destination directory path. When only a directory is given, the copied file keeps its original name:
cp file.txt /backupTo copy the file to a different directory under a new name, include the file name in the destination path:
cp file.txt /backup/new_file.txtOverwrite Behavior
By default, cp overwrites the destination file if it already exists. On current GNU systems, use --update=none to skip existing files without treating skipped files as errors:
cp --update=none file.txt file_backup.txtThe older -n (--no-clobber) option is still common in examples, but GNU coreutils now treats it as deprecated shorthand for --update=none.
To prompt for confirmation before overwriting, use the -i (--interactive) option:
cp -i file.txt file_backup.txtcp: overwrite 'file_backup.txt'?To copy only when the source is newer than the destination, use -u (--update):
cp -u file.txt file_backup.txtThe longer --update=UPDATE form gives finer control over which existing files are replaced:
older- Replace the destination only when it is older than the source. This is the default when--updateis given on its own, and what plain-udoes.all- Replace every existing destination file, which is the normal behavior without--update.none- Skip every existing destination without reporting an error.none-fail- Skip every existing destination, print a diagnostic, and exit with a failure status.
--update=UPDATE form needs GNU coreutils 9.3 or later. Although none-fail was introduced in 9.5, a bug caused cp to reject it until coreutils 9.6. On older systems such as Ubuntu 22.04 (coreutils 8.32) or Debian 12 (9.1), the option is rejected as unrecognized, and Ubuntu 24.04 (9.4) accepts every value except none-fail. Check your version with cp --version.By default, cp already overwrites the destination, so the -f (--force) option is not needed for a normal overwrite. It matters when the destination file cannot be opened, for example a read-only file: -f removes that file and copies the source in its place.
cp -f file.txt file_backup.txtIf your shell aliases cp to cp -i, cp -f may still prompt because the alias adds -i before your option. Bypass the alias when you need the exact command:
command cp -f file.txt file_backup.txtPreserve File Attributes
When cp creates a new file, it is owned by the user running the command with a timestamp of the current time. Use the -p (--preserve) option to preserve the file mode, ownership
, and timestamps
from the source:
cp -p file.txt file_backup.txtThe --preserve=ATTR_LIST form selects individual attributes. The list is comma separated and accepts mode for permissions, including any ACL and extended-attribute permissions, ownership for user and group, timestamps for the file timestamps, links for hard links between the copied files, context for the SELinux security context, xattr for extended attributes, and all for everything:
cp --preserve=timestamps,mode file.txt file_backup.txtPlain -p is shorthand for --preserve=mode,ownership,timestamps. An ordinary user can preserve group ownership only when they belong to the source group, and cannot change a file to another user. If a requested attribute cannot be preserved, cp prints a diagnostic and may exit with a failure status even though it copied the file contents.
Create Backups
When the destination already exists and the old version is worth keeping, the -b option renames it out of the way before the copy is made:
cp -b file.txt /backup/file.txtThe backup keeps the original name with a tilde (~) appended, so the previous contents are now in /backup/file.txt~. Use --suffix for a different ending:
cp -b --suffix=.orig file.txt /backup/file.txtThe --backup=CONTROL form decides how those backups are named. GNU cp accepts these values:
noneoroff- Do not make backups at all.numberedort- Make numbered backups such asfile.txt.~1~andfile.txt.~2~.existingornil- Use numbered backups when numbered ones are already present, and a simple backup otherwise.simpleornever- Always make a simple backup with the suffix appended.
Numbered backups suit a file that gets copied into place over and over, because each run keeps the earlier version instead of overwriting a single file.txt~:
cp --backup=numbered file.txt /backup/file.txtVerbose Output
Use the -v (--verbose) option to print each file as it is copied:
cp -v file.txt file_backup.txt'file.txt' -> 'file_backup.txt'Copy-on-Write Copies
On filesystems that support copy-on-write, such as Btrfs, XFS, and bcachefs, cp does not have to duplicate all the data blocks. It shares the existing blocks and writes new ones only when one of the copies is modified, so copying a large file is nearly instant and initially uses only a small amount of additional space for filesystem metadata.
In GNU coreutils 9.0 and later, cp behaves as if --reflink=auto were given, which means it tries the lightweight copy and falls back to a full one where the filesystem cannot do it. When you would rather see the command fail than silently duplicate several gigabytes, ask for the clone explicitly:
cp --reflink=always disk.img disk-clone.imgPassing --reflink=never goes the other way and forces a full copy of the data. Reflinked files share data blocks while those blocks remain unchanged, so an I/O error affecting a shared block can affect both files. Use a full copy on separate storage when the goal is an independent backup.
Copy a Directory
To copy a directory and all its contents recursively, use the -R or -r option:
cp -R Pictures Pictures_backupIf Pictures_backup does not exist, cp creates it and copies the contents of Pictures into it. If Pictures_backup already exists, Pictures itself is copied inside it, resulting in Pictures_backup/Pictures/.
To copy a directory and preserve everything, including permissions, ownership, timestamps, and symbolic links, use the -a (--archive) option. It is equivalent to -dR --preserve=all and is the standard choice when the copied tree needs to retain filesystem attributes:
cp -a Pictures Pictures_backupRecursive Copy Compared With Archive Copy
A plain cp -R copies the tree but stamps every new file with the current time and your own ownership. Adding -p covers the common cases, which is why the combined forms cp -pr and cp -rp appear so often:
cp -pr Pictures Pictures_backupThat preserves mode, ownership, and timestamps, and symbolic links stay links, because -R does not follow symbolic links in the source by default. What it leaves behind is hard links between the copied files, extended attributes, and the SELinux security context. The -a option carries those across as well, since it expands to -dR --preserve=all. For copies intended for later restoration, prefer -a so this metadata is retained.
The -f option often turns up in the same position, as in cp -rf, and it changes nothing about a normal overwrite. See Overwrite Behavior
for what it actually does.
Symbolic Links in the Source
Without -R, cp follows a symbolic link and copies the file it points to, so cp link.txt copy.txt leaves you with a regular file. Recursive copies work the other way and recreate links as links. Four options override the default:
-L- Follow every symbolic link and copy the data it points to, including links found inside the tree.-P- Never follow symbolic links, and copy each one as a link.-H- Follow only the links named on the command line, and copy links found inside the tree as links.-d- Copy links as links and preserve hard links between the copied files. It is shorthand for--no-dereference --preserve=linksand is part of what-adoes.
Resolving the links is useful when the copy is headed for a machine where the targets do not exist:
cp -RL site site_snapshotEvery link inside site is replaced by the file it pointed to, so site_snapshot holds real data instead of pointers. Check what those links point at first. A link to a large directory elsewhere on the system pulls all of that data into the copy.
Copy Directory Contents
Copying what is inside a directory, without the directory itself coming along, is where cp surprises people most. As shown above, cp -R Pictures Pictures_backup creates Pictures_backup/Pictures when the destination already exists, which is rarely the goal.
The shortest reliable form is a trailing /. on the source. It names the contents of the directory rather than the directory:
cp -a Pictures/. Pictures_backup/Hidden files come along, nothing is nested, and -a keeps permissions, ownership, and timestamps. The destination shown above ends in /, so it must already exist. Create it with mkdir
, or omit the destination’s trailing slash and let cp create it:
cp -a Pictures/. Pictures_backupUnlike rsync
, a plain trailing slash on the source changes nothing here. cp -a Pictures/ Pictures_backup/ still copies the directory itself, so it is the . in Pictures/. doing the work, not the slash.
The -T (no target directory) option reaches the same result from the other direction. It tells cp to treat the last argument as the final path rather than a container:
cp -RT Pictures Pictures_backupReach for /. when you want the source contents at the destination path, and for -T in scripts where you want to prevent an existing destination directory from changing where the source is placed.
A wildcard looks like the obvious answer and carries a trap:
cp -R Pictures/* Pictures_backup/The visible files are copied, but * never matches names that start with a dot, so anything like .config or .git is quietly left behind. Turn on the dotglob shell option first so patterns include hidden names:
shopt -s dotglob
cp -R Pictures/* Pictures_backup/
shopt -u dotglobThe last line switches the option back off, so later commands in the same shell session behave the way you expect.
Copy Multiple Files
To copy multiple files into a directory, list the sources followed by the destination directory as the last argument:
cp file.txt file1.txt /backupWhen copying multiple sources, the destination must be a directory. Directories in that list still need -R. Without it, cp copies the files, skips the directory, and exits with an error:
cp: -r not specified; omitting directory 'dir/'Add the option and the whole list is copied:
cp -R file.txt file1.txt dir/ /backupThe -t (target directory) option puts the destination first instead of last, which is what lets cp accept a list of file names from another command such as find
:
find /etc -name '*.conf' -exec cp -t /backup {} +Every file lands directly in /backup, so a nginx/nginx.conf and a ssh/ssh_config end up side by side and the directory structure is lost. The --parents option keeps the full source path under the destination:
cp --parents /etc/nginx/nginx.conf /backupThis creates /backup/etc/nginx/nginx.conf instead of /backup/nginx.conf.
-t and --parents options are GNU extensions. They are present on Linux distributions but not on macOS or most BSD systems.When a file name begins with a dash, cp reads it as an option. Put -- in front of the list to end option parsing:
cp -- -file.txt /backupCopy Files to a System Directory
Copying into a location such as /etc, /usr/local/bin, or a web root needs root privileges, so the command is normally run through sudo
:
sudo cp app.conf /etc/app/app.confIf the destination does not exist, sudo cp creates it as root, although its group can be inherited from the destination directory. If the destination file already exists, cp normally overwrites its contents in place and keeps its current ownership and mode.
Use -p only when the destination should keep the source ownership and mode. Because the command runs as root, this can leave a system file owned by the unprivileged user who owns the source:
sudo cp -p app.conf /etc/app/app.confWhen the destination needs a specific owner and mode regardless of what the source looks like, install sets both in a single command and avoids that ambiguity:
sudo install -m 644 -o www-data -g www-data app.conf /etc/app/app.confOverwriting a working system file deserves a little more care. Keep the old version with -b before replacing it:
sudo cp -b nginx.conf /etc/nginx/nginx.confThe previous file stays as /etc/nginx/nginx.conf~, which is enough to roll back when the service refuses to start. Ownership on a copy that is already in place can be corrected afterwards with chown
.
Quick Reference
For a printable quick reference, see the cp cheatsheet .
| Task | Command |
|---|---|
| Copy a file | cp source.txt dest.txt |
| Copy to a directory | cp file.txt /backup/ |
| Copy without overwriting | cp --update=none source.txt dest.txt |
| Prompt before overwriting | cp -i source.txt dest.txt |
| Copy only if source is newer | cp -u source.txt dest.txt |
| Force copy when destination cannot be opened | cp -f source.txt dest.txt |
| Preserve permissions and timestamps | cp -p source.txt dest.txt |
| Preserve selected attributes | cp --preserve=timestamps,mode source.txt dest.txt |
| Back up the destination before overwriting | cp -b source.txt dest.txt |
| Keep numbered backups | cp --backup=numbered source.txt dest.txt |
| Verbose output | cp -v source.txt dest.txt |
| Copy directory recursively | cp -R sourcedir/ destdir/ |
| Archive copy (preserve all attributes and symlinks) | cp -a sourcedir/ destdir/ |
| Copy directory contents into an existing directory | cp -a sourcedir/. destdir/ |
| Copy directory contents only | cp -RT sourcedir/ destdir/ |
| Resolve symbolic links while copying | cp -RL sourcedir/ destdir/ |
| Copy multiple files and directories | cp -R file1 file2 dir/ /dest/ |
| Target directory first, for use with find | cp -t /backup file1 file2 |
| Keep the source path under the destination | cp --parents /etc/app/app.conf /backup |
| Fail unless the filesystem can clone the data | cp --reflink=always disk.img clone.img |
| Copy a file whose name starts with a dash | cp -- -file.txt /backup |
Troubleshooting
cp: cannot stat 'source': No such file or directory
The source file or directory does not exist. Check the path for typos and confirm the file is present with ls -l source.
cp: -r not specified; omitting directory 'dirname'
You tried to copy a directory without the -R option. Add -R to copy recursively: cp -R sourcedir/ destdir/. Any plain files in the same command are still copied, and cp exits with a failure status.
cp: cannot copy a directory, 'dir', into itself, 'dir/backup'
The destination sits inside the directory being copied. Put the backup somewhere outside the source tree, or use --parents to build the path under a separate destination.
cp: cannot create regular file 'dest': Permission denied
You do not have write permission on the destination directory. Check permissions with ls -l and use sudo
if required, or change ownership with chown
.
cp: cannot open 'source' for reading: Permission denied
You do not have read permission on the source file. See Understanding Linux File Permissions
for how to inspect and adjust permissions.
cp: failed to clone 'dest' from 'source': Operation not supported
You used --reflink=always on a filesystem without copy-on-write support, such as ext4. Drop the option to let cp fall back to a normal copy.
The copied file is owned by root
A new destination created with sudo cp is normally owned by root, while an existing destination usually keeps its current owner. Use install -o to set ownership explicitly, or fix it afterwards with chown. Add -p only when the destination should inherit the source owner and mode.
FAQ
How do I copy a directory and all its contents?
Use the -R (recursive) option: cp -R sourcedir/ destdir/. Without -R, cp will refuse to copy a directory and print a warning. To land the contents in an existing directory rather than nesting the directory inside it, use cp -a sourcedir/. destdir/.
What is the difference between cp -pr and cp -a?
Both copy recursively and keep symbolic links as links. cp -pr preserves mode, ownership, and timestamps, while cp -a also preserves hard links, extended attributes, and the SELinux context, because it expands to -dR --preserve=all. Use -a for backups.
How do I copy files without overwriting existing ones?
Use --update=none: cp --update=none source.txt dest.txt. Files that already exist at the destination are silently skipped. On older systems, you will often see the same behavior written as cp -n source.txt dest.txt.
How do I preserve file permissions and timestamps when copying?
Use the -p option: cp -p source.txt dest.txt. This preserves the file mode, ownership, and timestamps from the original file.
What does cp -f do?
By default cp already overwrites existing files, so -f (--force) is not needed for a normal overwrite. It only matters when the destination cannot be opened, such as a read-only file, where cp removes it and copies the source instead. If cp is aliased to cp -i, use command cp -f source.txt dest.txt to bypass the alias.
What is the difference between cp and rsync?cp is the standard tool for local copies. rsync
is better for large transfers or keeping directories in sync because it skips files that have not changed, supports remote transfers over SSH, and can resume interrupted operations.
How do I copy hidden files with a wildcard?
The glob * does not match files starting with .. Run shopt -s dotglob in Bash before the copy so patterns include hidden names, then shopt -u dotglob afterwards. See Copy Directory Contents
for the alternatives that need no shell option at all.
What is the difference between cp and mv?cp creates a copy while leaving the original in place. mv
moves the file, removing it from the source location.
Conclusion
The cp command is the standard way to copy files and directories in Linux. Use -a for directories that will be restored later, sourcedir/. when the contents belong in an existing directory, and -i or --update=none to control what happens to files that are already there.
For copying files over a network, use the rsync
or scp
utilities.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page