rsync Cheat Sheet

Most used

These cover most copies, mirrors and backups:

rsync -av src/ dest/                      # copy contents of src into dest, keep metadata
rsync -avn --delete src/ dest/            # dry run of an exact mirror
rsync -av --delete src/ dest/             # exact mirror (removes extra files in dest)
rsync -avz src/ user@host:/srv/backup/    # push over SSH with compression
rsync -avP user@host:/var/log/app/ ./logs/  # pull with progress + resumable partials
rsync -av --exclude='node_modules' proj/ /mnt/usb/proj/

Syntax: rsync [options] SRC... DEST. Either side can be remote (user@host:path), which uses SSH by default. rsync only sends the differences between source and destination, so a second run of the same command is fast. It is installed by default on most distros; otherwise sudo apt install rsync, sudo dnf install rsync, sudo pacman -S rsync or sudo zypper install rsync. Remote transfers need rsync installed on both machines.

The trailing slash matters

rsync -a photos dest/ creates dest/photos/. rsync -a photos/ dest/ puts the files straight into dest/. Combined with --delete, the wrong one can wipe a directory. Run with -n first.

Core options

CommandWhat it does
rsync -a src/ dest/Archive mode: recursive, keeps permissions, times, symlinks, owner and group (owner needs root)
rsync -av src/ dest/Same, listing every file transferred
rsync -r src/ dest/Recursive only, without preserving metadata
rsync -aH src/ dest/Also preserve hard links
rsync -aAX src/ dest/Also preserve ACLs and extended attributes (SELinux labels, capabilities)
rsync -aAXH --numeric-ids src/ dest/Full-fidelity system copy; keep UIDs/GIDs as numbers
rsync -az src/ host:dest/Compress data in transit (helps on slow links, not on LAN)
rsync -a --info=progress2 src/ dest/One overall progress line instead of per-file output
rsync -aP src/ dest/-P = --partial --progress: per-file progress, keep partial files
rsync -ah --stats src/ dest/Print a summary with human-readable sizes
rsync -ai src/ dest/Itemize changes: shows why each file is sent

Dry runs and comparing

CommandWhat it does
rsync -avn src/ dest/Dry run: show what would be copied, change nothing
rsync -ain --delete src/ dest/Dry run of a mirror; lines starting *deleting would be removed
rsync -avc src/ dest/Compare by checksum instead of size + time (slower, catches silent changes)
rsync -avnc src/ dest/Verify a backup: list files whose content differs
rsync -a --size-only src/ dest/Skip files with the same size, ignore timestamps
rsync -a --modify-window=2 src/ /mnt/fat/Tolerate 2-second timestamp precision on FAT/exFAT drives

Deleting and mirroring

CommandWhat it does
rsync -a --delete src/ dest/Delete files in dest that are not in src
rsync -a --delete-after src/ dest/Delete after the transfer finishes (safer if the run is interrupted)
rsync -a --delete-excluded src/ dest/Also delete files in dest that match your excludes
rsync -a --delete --max-delete=50 src/ dest/Abort deletions after 50 files (guard against a wrong path)
rsync -a --delete --backup --backup-dir=../old-$(date +%F) src/ dest/Move replaced and deleted files into a dated folder instead of losing them
rsync -a --remove-source-files src/ dest/Move: delete source files after they are copied (directories stay)
rsync -a --ignore-existing src/ dest/Never overwrite files that already exist in dest
rsync -au src/ dest/Update: skip files that are newer in dest

Remote transfers over SSH

CommandWhat it does
rsync -av src/ user@host:/path/Push local files to a remote host
rsync -av user@host:/path/ dest/Pull remote files to the local machine
rsync -av -e 'ssh -p 2222' src/ host:/path/Use a non-standard SSH port
rsync -av -e 'ssh -i ~/.ssh/backup_ed25519' src/ host:/path/Use a specific key
rsync -av host:'/path/with space/' dest/Quote remote paths that contain spaces
rsync -av --rsync-path='sudo rsync' src/ host:/etc/app/Run rsync as root on the remote side (needs passwordless sudo for rsync)
rsync -av --bwlimit=5m src/ host:/path/Limit bandwidth to about 5 MB/s
rsync -av --mkpath src/ host:/new/deep/path/Create missing destination directories (rsync 3.2.3+)
rsync -av host1:/a/ host2:/b/Not supported: one side must be local. Run rsync on one of the hosts instead.

Key-based login makes unattended rsync jobs possible; set it up with the SSH keys guide. More SSH options are in the ssh cheat sheet.

Include and exclude filters

CommandWhat it does
--exclude='*.tmp'Skip files matching a pattern anywhere in the tree
--exclude='/cache/'Leading / anchors to the top of the source; trailing / matches directories only
--exclude={'.git','node_modules','*.log'}Several excludes via bash brace expansion
--exclude-from=excludes.txtRead patterns from a file, one per line
--include='*/' --include='*.jpg' --exclude='*'Copy only .jpg files but keep the directory structure (order matters)
-m (--prune-empty-dirs)Drop directories that end up empty after filtering
-C (--cvs-exclude)Skip VCS directories (.git, .svn, .hg) and build junk such as *.o and *~
--files-from=list.txtCopy only the paths listed in a file (relative to the source)
--max-size=100m / --min-size=1kSkip files above or below a size

Common recipes

Back up your home directory to a USB drive, skipping caches. The full script with logging is at rsync home backup script:

rsync -aAXh --delete --info=progress2 \
  --exclude={'.cache','Downloads','.local/share/Trash'} \
  ~/ /media/$USER/backup/home/

Snapshot-style incremental backups where unchanged files are hard links to the previous run:

today=$(date +%F)
rsync -a --delete --link-dest=/backup/latest ~/ /backup/$today/
ln -sfn /backup/$today /backup/latest

Copy a whole system to a new disk (run from a live USB, both mounted):

sudo rsync -aAXHv --numeric-ids \
  --exclude={'/dev/*','/proc/*','/sys/*','/tmp/*','/run/*','/mnt/*','/media/*','/lost+found'} \
  /mnt/old/ /mnt/new/

Deploy a static site and only upload what changed:

rsync -avz --delete --exclude='.git' public/ deploy@web1:/var/www/site/

Resume a huge file over a flaky connection:

rsync -avP --append-verify bigfile.iso user@host:/data/

Check how much will be transferred before starting (compare to free space with du and df):

rsync -an --stats src/ dest/ | grep -E 'Number of regular files transferred|Total transferred file size'

Gotchas

  • Trailing slash on the source. src/ means "the contents of src". The slash on the destination does not matter.
  • --delete plus a wrong path is destructive. Always do a -n run first, and consider --max-delete or --backup-dir in scheduled jobs.
  • Owners are only kept as root. As a normal user, -a silently sets you as the owner on the destination. Use sudo rsync for system files, and --numeric-ids when the user names differ between machines.
  • FAT, exFAT and NTFS drives cannot store Linux permissions. You get errors like chown failed: Operation not permitted. Use -rltv instead of -a, and --modify-window=2 for FAT. See Operation not permitted.
  • -z on a fast LAN slows things down because the CPU becomes the bottleneck. Use it on internet links only.
  • Unescaped spaces in remote paths. Quote the remote path; rsync 3.2.4+ handles it without extra backslashes, older versions needed -s (--protect-args).
  • rsync is not a backup by itself. A mirror copies your mistakes too. Keep dated copies with --link-dest or use snapshots (Timeshift and Snapper).

Every option is documented in the rsync manual.

Frequently asked questions

What is the difference between rsync src and src/?

Without the trailing slash rsync copies the directory itself, so rsync -a src dest/ creates dest/src/. With it, rsync -a src/ dest/ copies only the contents of src into dest.

How do I see what rsync will do before running it?

Add -n (--dry-run) together with -v or -i. Nothing is transferred or deleted, but rsync lists every change it would make.

Does rsync delete files on the destination?

Not by default. Only --delete (and its variants) removes files from the destination that no longer exist in the source. Always test it with -n first.

How do I use rsync with a different SSH port or key?

Pass the SSH command with -e: rsync -a -e 'ssh -p 2222 -i ~/.ssh/backup_key' src/ user@host:/backup/.

Can rsync resume an interrupted transfer?

Yes. Rerun the same command; rsync skips files that are already complete. Add --partial (or -P) so half-transferred large files are kept and continued instead of restarted.

Spotted a mistake or a command that no longer works? Send a correction — pages are re-checked when reports come in.