cp — Copy Files & Directories Linux coreutils
Copying is one of the most common "safe operations" on a VPS: you duplicate config files before editing, snapshot a WordPress folder before upgrading, or move content into a staging area.
cp (copy) is the standard command for duplicating files and directories—fast, scriptable, and full of safety controls.
cp- You want a quick backup copy before making changes
- You need to duplicate themes, plugins, or uploads for staging
- You're building automation scripts that assemble folders and files
For large site moves or syncing huge directories repeatedly, prefer rsync — it's more efficient and supports incremental, bandwidth-aware transfers.
Prerequisites
- Linux VPS (Ubuntu recommended)
- SSH access with file-level permissions (or
sudo) - Familiarity with paths (e.g.,
/var/www/html/wp-content/)
Verify cp is Installed
which cp
Expected output:
/usr/bin/cp
Check version:
cp --version
Expected output:
cp (GNU coreutils) 9.4
Complete Syntax
cp [OPTION]... SOURCE DEST
cp [OPTION]... SOURCE... DIRECTORY
cp [OPTION]... -t DIRECTORY SOURCE...
| Form | Description |
|---|---|
cp SOURCE DEST | Copy a single file to a new name or location |
cp SOURCE... DIRECTORY | Copy multiple files into a directory |
cp -t DIRECTORY SOURCE... | Specify the destination first (useful in scripts) |
cp -r SOURCE DEST | Copy a directory recursively |
cp -a SOURCE DEST | Archive copy — recursive + preserve all metadata |
SOURCEcan be a file, multiple files, or a directory (with-r/-a)DESTmust be a directory when copying multiple sources- Without
-ror-a, directories are silently skipped with an error
Options Reference
| Option | Meaning | Best For |
|---|---|---|
-r | Copy directories recursively | Copy folders (basic) |
-a | Archive mode (recursive + preserve all metadata) | Backups |
-p | Preserve mode, ownership, and timestamps | Config backups / migrations |
-u | Copy only if source is newer than destination | Incremental updates |
-i | Prompt before overwrite | Manual safety |
-n | Never overwrite existing files | Automation safety |
-f | Force overwrite without prompting | Deploy scripts (use carefully) |
-v | Verbose: print each file as it is copied | Logs / debugging |
-l | Create hard links instead of copying | Save disk space |
-s | Create symbolic links instead of copying | Quick aliasing |
--parents | Preserve the full source path in destination | Structured backups |
--remove-destination | Remove destination file before writing | Avoid permission edge cases |
--backup | Make a backup of each existing destination file | Safe overwrites |
--help | Show help and exit | Quick reference |
--version | Show version and exit | Compatibility checks |
-a is the safe default for backupscp -a is equivalent to cp -dR --preserve=all. It copies recursively and preserves all metadata — the best choice for WordPress directory backups.
Quick Decision Table
| Goal | Recommended Command |
|---|---|
| Backup a folder reliably | cp -a source/ backup/ |
| Copy a folder quickly (no metadata concern) | cp -r source/ dest/ |
| Avoid overwriting existing files | cp -n source dest |
| Ask before overwriting (manual work) | cp -i source dest |
| Update only when source is newer | cp -u source dest |
| Keep exact folder structure in backup | cp --parents path/to/file /backup-root/ |
| Force overwrite in deploy scripts | cp -f source dest |
| Preserve path and avoid permission issues | cp --remove-destination source dest |
Safety & Automation Patterns
- Backup (recommended)
- Safe automation
- Manual safety
- Update only if newer
cp -a /var/www/html/wp-content/ /backups/wp-content/
Copies the entire wp-content directory with all permissions, ownership, and timestamps intact.
cp -n wp-config.php /backups/
Skips the copy if /backups/wp-config.php already exists. Safe default for scripts.
cp -i wp-config.php wp-config.php.bak
Prompts before overwriting. Use this during manual maintenance.
cp -u new-style.css /var/www/html/wp-content/themes/mytheme/
Only copies if new-style.css is newer than the existing destination file.
Best Practices
- Prefer
cp -afor backups — it's recursive and preserves all metadata. - Use
-nin automation scripts to prevent accidental overwrites silently. - Use
-iduring manual work when you're unsure of the destination state. - Use
--parentswhen you want backups that mirror the original path structure. - Always verify results with
ls -lahto confirm permissions and ownership. - Combine
-vwith-awhen debugging backup scripts to trace what was copied. - For repeated or large sync operations, switch to
rsyncinstead.
-f overwrites without askingcp -f destroys the destination silently. Always combine with -v for visibility in scripts, and double-check your target paths.
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
-r not specified; omitting directory | Source is a directory, no -r given | Add -r or use -a |
| File overwritten unexpectedly | Used -f or forgot -i/-n | Use -n or -i next time |
| Wrong permissions after copy | Metadata not preserved | Use cp -a or cp -p |
Permission denied | Insufficient read/write access | Use sudo or fix ownership |
| Destination file is empty | Source is a symlink or zero-byte file | Verify with stat source |
Verification commands
# View destination contents and metadata
ls -lah /path/to/dest
# Check a specific file's permissions and owner
ls -l /path/to/dest/file
# Compare timestamps between source and destination
stat source_file dest_file
# Confirm the copy succeeded and nothing was skipped
diff -r source_dir dest_dir
Cheat Sheet
cp file1 file2 # Copy file to a new name
cp file1 file2 /dst/ # Copy multiple files into a folder
cp -r folder/ backup/ # Copy directory recursively
cp -a /var/www/html/wp-content/ /bak/ # Best for backups (archive mode)
cp -i wp-config.php /backups/ # Prompt before overwrite
cp -n style.css themes/ # Skip if destination exists
cp -u new.css themes/ # Copy only if source is newer
cp -v config.php /backups/ # Verbose: show what is being copied
cp --parents a/b/c.txt /backup/ # Preserve full path structure
cp -f index.php /var/www/html/ # Force overwrite
cp -a .htaccess .user.ini /backups/ # Copy dotfiles with metadata
cp -r {plugins,themes} /backups/ # Copy multiple dirs (brace expansion)
cp wp-config.php wp-config-$(date +%Y-%m-%d).bak # Versioned backup
Mini Quiz
- Which flag is the best "backup mode" for directories?
- What is the difference between
cp -randcp -a? - How do you copy a file only if the source is newer?
- Which flag prevents overwriting existing files silently?
- What happens if you run
cpon a directory without-ror-a?
-a— it is recursive and preserves all metadata-ronly recurses;-aalso preserves permissions, ownership, and timestamps-u-ncpskips the directory and prints:-r not specified; omitting directory
Worked Examples
Examples are ordered from basic to advanced so you build understanding progressively before reaching production patterns.
Copy a Single File
cp index.php index.bak.php
Expected output: (silent success)
Copy Multiple Files into a Directory
cp style.css script.js functions.php /var/www/html/wp-content/themes/mytheme/
Expected output: (silent success)
Copy a Directory Without -r (Failure Case)
cp wp-content /backups/
Expected output:
cp: -r not specified; omitting directory 'wp-content'
Copy a Directory Recursively (-r)
cp -r wp-content /backups/
Expected output: (silent success)
Verbose Output (-v)
cp -v index.php index_copy.php
Expected output:
'index.php' -> 'index_copy.php'
Interactive Overwrite Prompt (-i)
cp -i wp-config.php wp-config.php.bak
Expected output (if destination exists):
cp: overwrite 'wp-config.php.bak'?
Copy Only if Newer (-u)
cp -u new-style.css /var/www/html/wp-content/themes/mytheme/
Expected output: (silent success; skips if destination is up-to-date)
Preserve Attributes (-p)
cp -p wp-config.php /backups/
Expected output: (silent success; ownership and timestamps preserved)
Archive Mode (-a) — Recommended for Backups
cp -a /var/www/html/wp-content /backups/
Expected output: (silent success; full metadata preserved)
No Overwrite (-n)
cp -n style.css /var/www/html/wp-content/themes/mytheme/
Expected output: (silent success; skips if file already exists)
Preserve Full Path (--parents)
cp --parents wp-content/plugins/akismet/akismet.php /backups/
Expected output — resulting path created:
/backups/wp-content/plugins/akismet/akismet.php
Force Overwrite (-f)
cp -f index.php /var/www/html/
Expected output: (silent success)
This overwrites the destination without prompting. Use only in controlled deploy scripts.
Remove Destination Before Copying (--remove-destination)
cp --remove-destination index.php /var/www/html/
Expected output: (silent success; avoids permission conflicts on immutable files)
Copy All .php Files with Wildcard
cp *.php /var/www/html/wp-content/plugins/custom-plugin/
Expected output: (silent success)
Copy Hidden Files (Dotfiles)
cp -a .htaccess .user.ini /backups/
Expected output: (silent success; dotfiles copied with full metadata)
Copy to Another User's Home (Requires sudo)
sudo cp wp-config.php /home/developer/
Expected output: (silent success)
Copy and Rename in One Command
cp wp-config.php wp-config-2025.php
Expected output: (silent success)
Copy Multiple Directories with Brace Expansion
cp -r {plugins,themes} /backups/
Expected output: (silent success)
Versioned Backup with Date in Filename
cp wp-config.php wp-config-$(date +%Y-%m-%d).bak
Expected output: (silent success; filename includes today's date)
Clone Live Site into Staging
cp -a /var/www/html /var/www/staging/
Expected output: (silent success)
Cloning a full WordPress site can be large. Confirm available disk space first with df -h.