cp, mv, rsync: Copying Files Right
You’ll move files around constantly. Three commands cover 99% of the need: cp (copy), mv (move/rename), and rsync (smart copy that handles networks, incremental updates, and resumes).
cp: copy files
cp source.txt destination.txt
cp source.txt /tmp/ # copy into a directory
cp file1 file2 file3 /backup/ # multiple sources, one dest
cp -r project/ project-backup/ # recursive (for directories)
cp -p source dest # preserve timestamps + permissions
cp -a source dest # archive mode: preserve everything
cp -i source dest # interactive — ask before overwrite
cp -u source dest # only overwrite if source is newer
cp -v source dest # verbose
Useful combos
cp -av project/ /backup/ # backup with everything preserved
cp -ru new-config/ /etc/myapp/ # update only changed files
mv: move or rename
The same command renames AND moves. Linux makes no distinction.
mv old-name new-name # rename
mv file.txt /tmp/ # move
mv file1 file2 /backup/ # multiple files, one dest
mv -i file.txt /tmp/ # ask before overwrite
mv -n file.txt /tmp/ # NEVER overwrite (no clobber)
mv -v file.txt /tmp/ # verbose
Rename with patterns
Bash brace expansion is great for renaming:
mv myfile.{txt,bak} # mv myfile.txt myfile.bak
# Rename many files at once with rename or for-loop
for f in *.JPG; do mv "$f" "${f%.JPG}.jpg"; done
rsync: the right tool for serious copies
rsync is what you want for backups, syncing folders, copying over the network, or anything where you might want to resume / re-run.
Local rsync
# Copy directory contents (note trailing slashes — they matter!)
rsync -av source/ destination/
# Mirror — make destination identical to source (deletes extras)
rsync -av --delete source/ destination/
# Dry run — show what WOULD happen
rsync -avn --delete source/ destination/
Trailing slash gotcha
This is the #1 rsync mistake.
rsync -av source/ dest/— copies CONTENTS of source into destrsync -av source dest/— copies the source FOLDER ITSELF into dest (creates dest/source/…)
rsync over SSH
# Copy local to remote
rsync -avz ./project/ user@server:/opt/project/
# Copy remote to local
rsync -avz user@server:/var/log/ ./logs/
# Resume a partial transfer (huge files, flaky network)
rsync -avz --partial --progress big.iso user@server:/data/
Useful rsync flags
-a archive mode (recursive + permissions + timestamps + symlinks)
-v verbose
-z compress during transfer (saves bandwidth)
-h human-readable sizes
-P progress + partial (resume support)
--delete remove files in dest that aren't in source
--exclude='*.log' skip files matching pattern
--dry-run / -n show what would happen without doing it
--bwlimit=10000 limit to 10 MB/s
scp: simple SSH copy
Old, simple, less powerful than rsync. Still works.
scp file.txt user@server:/tmp/
scp -r project/ user@server:/opt/
scp user@server:/var/log/syslog ./
Use rsync instead if you have it. scp is being deprecated.
cp vs rsync vs scp
| Use case | Tool |
|---|---|
| Local copy, small set of files | cp |
| Local copy, big tree | rsync (faster on re-runs) |
| Backup script (incremental) | rsync |
| Sync code to server | rsync over SSH |
| One file to remote | scp or rsync |
| Resume an interrupted huge copy | rsync –partial |
Common mistakes
cp file destinationwhen destination doesn’t exist — creates a file with the dest name (might not be what you wanted).- Forgetting
-ron cp for directories — “cp: -r not specified; omitting directory”. - rsync trailing slash confusion — read the section above twice.
rsync --deleteon the wrong direction — wipes files you wanted to keep. Always--dry-runfirst.
What to learn next
Symbolic and hard links are how Linux handles “this file should appear in two places” without actually copying the data. Coming up next.