The
cp
command copies files and directories. It is one of the most frequently used commands on any Linux server, whether you are making a backup of a configuration file before editing it, duplicating a WordPress installation, or copying assets between directories. The syntax is straightforward but there are flags and behaviors worth understanding, especially around permissions, overwriting, and recursive copying.
This guide covers
cp
for files and directories,
mv
for moving and renaming, and the related commands for creating and viewing files that come up in the same workflows.
Copying a single file#
cp source.txt destination.txt
This creates a copy of
source.txt
named
destination.txt
in the same directory. If
destination.txt
already exists, it is overwritten without warning.
Copy to a different directory
cp source.txt /home/user/backups/
Copies
source.txt
into the
/home/user/backups/
directory, keeping the original filename. The trailing slash is not required but makes the intent clearer.
cp source.txt /home/user/backups/source-backup.txt
Copies and renames in one step.
Copy multiple files to a directory
cp file1.txt file2.txt file3.txt /home/user/backups/
All three files are copied into the destination directory. The destination must be a directory when copying multiple files.
Using a wildcard:
cp *.txt /home/user/backups/
Copies all
.txt
files in the current directory.
Copying directories with -r#
cp
does not copy directories by default:
cp mydir /home/user/backups/
cp: -r not specified; omitting directory 'mydir'
You need the
-r
(recursive) flag:
cp -r mydir /home/user/backups/
This copies
mydir
and everything inside it, including subdirectories and their contents, into the destination. The result is
/home/user/backups/mydir/
with all contents intact.
Copy directory contents without the directory itself
cp -r mydir/* /home/user/backups/
This copies the contents of
mydir
into
backups/
without creating a
mydir
subdirectory at the destination. Note that
*
does not match hidden files (dotfiles). To include them:
cp -r mydir/. /home/user/backups/
The
/.
pattern matches everything including hidden files.
Preserving permissions and timestamps#
By default,
cp
creates the new file with the current user’s default permissions and the current timestamp. The copy does not inherit the original file’s permissions, ownership, or modification time.
Preserve with -p
cp -p source.txt destination.txt
The
-p
flag preserves the original file’s mode (permissions), ownership, and timestamps. This matters when copying configuration files, WordPress files, or anything where file permissions need to remain intact.
Preserve everything with -a (archive)
cp -a mydir /home/user/backups/
The
-a
flag is equivalent to
-r -p --preserve=all
. It copies recursively, preserves permissions, timestamps, ownership, and symbolic links. This is the flag to use when making a backup copy of a directory where you want the copy to be identical to the original.
For WordPress backups:
cp -a /var/www/html/wp-content /home/user/wp-content-backup
This preserves the ownership (usually
www-data
) and permissions (usually 755 for directories, 644 for files) that WordPress requires. Without
-a
, you would need to manually fix permissions after copying. For large directory trees or remote copies, rsync is more efficient than
cp -a
because it can resume interrupted transfers and skip unchanged files.
Overwrite protection#
Prompt before overwriting with -i
cp -i source.txt destination.txt
If
destination.txt
exists,
cp
asks for confirmation:
cp: overwrite 'destination.txt'? y
This is useful when you are not sure whether the destination already contains important data.
Never overwrite with -n
cp -n source.txt destination.txt
If
destination.txt
exists,
cp
silently skips the copy. No prompt, no error, no overwrite. Useful in scripts where you want to copy only if the file does not already exist.
Only overwrite if source is newer with -u
cp -u source.txt destination.txt
The
-u
flag copies only if the source file is newer than the destination file, or if the destination does not exist. Useful for incremental backups where you only want to update files that have changed.
Verbose output with -v#
cp -rv mydir /home/user/backups/
The
-v
flag prints each file as it is copied:
'mydir/file1.txt' -> '/home/user/backups/mydir/file1.txt'
'mydir/file2.txt' -> '/home/user/backups/mydir/file2.txt'
'mydir/subdir/file3.txt' -> '/home/user/backups/mydir/subdir/file3.txt'
Useful for verifying that the right files are being copied, especially with wildcard patterns or recursive copies.
Moving and renaming files with mv#
mv
moves a file from one location to another. If the source and destination are on the same filesystem, this is nearly instant because
mv
just updates the directory entry without copying any data. If they are on different filesystems,
mv
copies the file and then deletes the original.
Move a file
mv source.txt /home/user/documents/
The file is removed from the current directory and placed in the destination.
Rename a file
mv oldname.txt newname.txt
Moving within the same directory is a rename. There is no separate
rename
command needed for single files.
Move a directory
mv mydir /home/user/backups/
Unlike
cp
,
mv
works on directories without a
-r
flag. The entire directory tree is moved.
mv vs cp
The key difference:
mv
removes the original,
cp
does not. Use
cp
when you want to keep the original. Use
mv
when you want to relocate or rename.
# Backup before editing (use cp - keep the original)
cp wp-config.php wp-config.php.bak
# Rename a log file for rotation (use mv - replace the original)
mv access.log access.log.old
Creating files#
touch
touch newfile.txt
Creates an empty file if it does not exist. If the file already exists,
touch
updates its modification timestamp without changing its contents. This is useful for creating placeholder files or updating timestamps that trigger build systems or cron checks.
Create with content using echo
echo "Hello world" > newfile.txt
Creates the file with the specified content. The
>
operator overwrites the file if it exists. Use
>>
to append instead of overwrite:
echo "Another line" >> newfile.txt
Create with a heredoc
For multi-line content:
cat > config.txt << 'EOF'
server_name=example.com
port=8080
debug=false
EOF
This creates
config.txt
with the three lines between
<< 'EOF'
and
EOF
. The single quotes around
EOF
prevent variable expansion in the content.
Viewing file contents#
cat
cat filename.txt
Prints the entire file to the terminal. Fine for small files. For large files, the output scrolls past faster than you can read it.
less
less filename.txt
Opens the file in a scrollable viewer. Navigate with arrow keys, search with
/pattern
, and quit with
q
. This is the standard way to read log files and configuration files on a server. Unlike
cat
,
less
does not load the entire file into memory, so it works fine on gigabyte-sized log files.
head and tail
head -20 filename.txt
Shows the first 20 lines. Useful for checking the top of a log file or configuration file.
tail -20 filename.txt
Shows the last 20 lines. Useful for checking recent log entries.
tail -f /var/log/nginx/access.log
The
-f
flag follows the file in real time, printing new lines as they are appended. This is how you watch a log file live while testing something. Press
Ctrl+C
to stop.
Finding files#
If you need to find a file before copying it:
find /var/www -name "wp-config.php"
This searches recursively under
/var/www
for files named
wp-config.php
. For a complete guide on finding files by name, size, date, and permissions, see Linux find command: how to find files and processes.
Common WordPress file operations#
Backup wp-config.php before editing
cp -p /var/www/html/wp-config.php /var/www/html/wp-config.php.bak
Always make a backup before editing configuration files. The
-p
flag preserves permissions so the backup has the same access rights as the original.
Copy a plugin between sites
cp -a /var/www/site1/wp-content/plugins/my-plugin /var/www/site2/wp-content/plugins/
The
-a
flag preserves the ownership and permissions. After copying, verify the ownership matches what the destination site expects:
ls -la /var/www/site2/wp-content/plugins/my-plugin
Copy uploads to a backup location
cp -a /var/www/html/wp-content/uploads /home/user/uploads-backup-$(date +%Y%m%d)
The
$(date +%Y%m%d)
appends today’s date to the backup directory name, making it easy to identify when the backup was taken.
For transferring files between servers rather than copying locally, see How to transfer files over SSH using SCP or SFTP commands: a complete reference guide.
Quick reference#
# Copy a file
cp source.txt destination.txt
# Copy to a directory
cp source.txt /path/to/directory/
# Copy a directory recursively
cp -r mydir /path/to/destination/
# Copy preserving permissions and timestamps
cp -p source.txt destination.txt
# Archive copy (recursive + preserve everything)
cp -a mydir /path/to/backup/
# Copy with overwrite prompt
cp -i source.txt destination.txt
# Copy only if source is newer
cp -u source.txt destination.txt
# Move/rename a file
mv oldname.txt newname.txt
# Create an empty file
touch newfile.txt
# View a file
cat file.txt # print entire file
less file.txt # scrollable viewer
head -20 file.txt # first 20 lines
tail -20 file.txt # last 20 lines
tail -f file.txt # follow in real time
| Command | What it does |
|---|---|
cp file dest
| Copy a file |
cp -r dir dest
| Copy a directory recursively |
cp -a dir dest
| Archive copy (preserves everything) |
cp -p file dest
| Preserve permissions and timestamps |
cp -i file dest
| Prompt before overwriting |
cp -n file dest
| Never overwrite existing files |
cp -u file dest
| Copy only if source is newer |
mv file dest
| Move or rename |
touch file
| Create empty file or update timestamp |