Linux cp Command: Copy Files and Directories

By 

Updated on

16 min read

Using the Linux cp command to 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:

txt
cp [OPTIONS] SOURCE... DESTINATION

SOURCE can be one or more files or directories. DESTINATION is a single file or directory. The behavior depends on what you pass:

  • When SOURCE and DESTINATION are both file paths, cp copies the source file to the destination. If the destination file does not exist, it is created.
  • When SOURCE contains multiple arguments, DESTINATION must be a directory. Each source file or directory is copied into it.
  • When SOURCE is a directory, use the -R option 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:

Terminal
cp file.txt file_backup.txt

Bash brace expansion offers a shorter form for the same operation:

Terminal
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:

Terminal
cp file.txt /backup

To copy the file to a different directory under a new name, include the file name in the destination path:

Terminal
cp file.txt /backup/new_file.txt

Overwrite 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:

Terminal
cp --update=none file.txt file_backup.txt

The 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:

Terminal
cp -i file.txt file_backup.txt
output
cp: overwrite 'file_backup.txt'?

To copy only when the source is newer than the destination, use -u (--update):

Terminal
cp -u file.txt file_backup.txt

The 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 --update is given on its own, and what plain -u does.
  • 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.
Info
The --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.

Terminal
cp -f file.txt file_backup.txt

If 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:

Terminal
command cp -f file.txt file_backup.txt

Preserve 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:

Terminal
cp -p file.txt file_backup.txt

The --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:

Terminal
cp --preserve=timestamps,mode file.txt file_backup.txt

Plain -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:

Terminal
cp -b file.txt /backup/file.txt

The 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:

Terminal
cp -b --suffix=.orig file.txt /backup/file.txt

The --backup=CONTROL form decides how those backups are named. GNU cp accepts these values:

  • none or off - Do not make backups at all.
  • numbered or t - Make numbered backups such as file.txt.~1~ and file.txt.~2~.
  • existing or nil - Use numbered backups when numbered ones are already present, and a simple backup otherwise.
  • simple or never - 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~:

Terminal
cp --backup=numbered file.txt /backup/file.txt

Verbose Output

Use the -v (--verbose) option to print each file as it is copied:

Terminal
cp -v file.txt file_backup.txt
output
'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:

Terminal
cp --reflink=always disk.img disk-clone.img

Passing --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:

Terminal
cp -R Pictures Pictures_backup

If 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:

Terminal
cp -a Pictures Pictures_backup

Recursive 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:

Terminal
cp -pr Pictures Pictures_backup

That 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.

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=links and is part of what -a does.

Resolving the links is useful when the copy is headed for a machine where the targets do not exist:

Terminal
cp -RL site site_snapshot

Every 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:

Terminal
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:

Terminal
cp -a Pictures/. Pictures_backup

Unlike 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:

Terminal
cp -RT Pictures Pictures_backup

Reach 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:

Terminal
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:

Terminal
shopt -s dotglob
cp -R Pictures/* Pictures_backup/
shopt -u dotglob

The 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:

Terminal
cp file.txt file1.txt /backup

When 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:

output
cp: -r not specified; omitting directory 'dir/'

Add the option and the whole list is copied:

Terminal
cp -R file.txt file1.txt dir/ /backup

The -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 :

Terminal
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:

Terminal
cp --parents /etc/nginx/nginx.conf /backup

This creates /backup/etc/nginx/nginx.conf instead of /backup/nginx.conf.

Info
The -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:

Terminal
cp -- -file.txt /backup

Copy 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 :

Terminal
sudo cp app.conf /etc/app/app.conf

If 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:

Terminal
sudo cp -p app.conf /etc/app/app.conf

When 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:

Terminal
sudo install -m 644 -o www-data -g www-data app.conf /etc/app/app.conf

Overwriting a working system file deserves a little more care. Keep the old version with -b before replacing it:

Terminal
sudo cp -b nginx.conf /etc/nginx/nginx.conf

The 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 .

TaskCommand
Copy a filecp source.txt dest.txt
Copy to a directorycp file.txt /backup/
Copy without overwritingcp --update=none source.txt dest.txt
Prompt before overwritingcp -i source.txt dest.txt
Copy only if source is newercp -u source.txt dest.txt
Force copy when destination cannot be openedcp -f source.txt dest.txt
Preserve permissions and timestampscp -p source.txt dest.txt
Preserve selected attributescp --preserve=timestamps,mode source.txt dest.txt
Back up the destination before overwritingcp -b source.txt dest.txt
Keep numbered backupscp --backup=numbered source.txt dest.txt
Verbose outputcp -v source.txt dest.txt
Copy directory recursivelycp -R sourcedir/ destdir/
Archive copy (preserve all attributes and symlinks)cp -a sourcedir/ destdir/
Copy directory contents into an existing directorycp -a sourcedir/. destdir/
Copy directory contents onlycp -RT sourcedir/ destdir/
Resolve symbolic links while copyingcp -RL sourcedir/ destdir/
Copy multiple files and directoriescp -R file1 file2 dir/ /dest/
Target directory first, for use with findcp -t /backup file1 file2
Keep the source path under the destinationcp --parents /etc/app/app.conf /backup
Fail unless the filesystem can clone the datacp --reflink=always disk.img clone.img
Copy a file whose name starts with a dashcp -- -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.

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

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