>_ josetilabs.com
← blog

02 Nov 2026 · infrastructure, linux · 4 min

Copy, sync and resume transfers with rsync

rsync does not copy file by file from scratch: it compares source and destination and transfers only the differences. With --partial it keeps what it already received and resumes from where it stopped. In a test with a 96 MB file, the transfer was cut at 6.2 MB and finished on the second try, with the sha256 hash identical to the original. See also backup with rsync and SSH keys instead of passwords.

Copy a folder

bash
rsync -a source/ destination/

The -a flag is archive mode: recursive, preserves permissions, timestamps, symbolic links and owner when possible. The trailing slash matters. source/ copies the contents into destination/; source without the slash creates destination/source/.

Real sync with –delete

bash
rsync -a --delete source/ destination/

--delete removes from the destination anything that no longer exists in the source. That is what turns a copy into a sync. The risk is swapping source and destination, so run the dry-run first.

Test first with –dry-run

bash
rsync -avn --delete source/ destination/

-n simulates the run and lists what it would do, including deletions, without touching anything. Typical output:

deleting extra.txt
./
file.txt
sent 123 bytes  received 20 bytes

If the list looks right, run the same command without -n.

Resume with –partial

bash
rsync -a --partial --progress source/ destination/

If the transfer is interrupted with Ctrl+C, the partial file stays in the destination. Running the same command again completes from where it stopped. For growing files (logs), use --append-verify, which checks the already copied part before continuing.

In the test, a 96 MB file was cut at 6.2 MB and finished on the second try; the destination sha256 matched the source.

Measuring the resume

The test file had 100,663,296 bytes (96 MiB) of random data. The first attempt was cut at 6.2 MiB with a 2 MB/s bandwidth limit. The second attempt completed the transfer and the destination sha256 matched the source: b5d99ebc9e42501f97f61169d4058abe6a89c12032f11a037d9ff3e07bd48e9f. The gain from --partial shows up when the source is remote or the network is unstable: instead of starting over, rsync reuses what already arrived.

Copy over ssh

bash
rsync -a -e ssh user@server:/path/source/ ./destination/
rsync -a -e "ssh -p 2222" ./source/ user@server:/path/destination/

-e sets the transport. Combine with --partial to resume an interrupted remote copy. For a specific key, use -e "ssh -i ~/.ssh/key".

Terminal with rsync -avn --delete listing the file that would be removed and the file that would be copied, without changing anything
rsync dry run: it shows what it would do, including the deletion, and touches no files.

Options worth knowing

How to verify

bash
rsync -avn --delete source/ destination/
sha256sum source/file destination/file

The dry-run lists changes without applying them. The hashes match when the copy finished without error.

If it goes wrong

Quick comparison

Tool Copies only differences Resumes Remote
cp no no no
scp no no yes (SSH)
rsync yes yes (--partial) yes (-e ssh)

FAQ

Does rsync copy hidden files? Yes. With -a, files starting with a dot are included.

Do I need rsync on both sides? For a remote copy, yes: the destination rsync receives the connection and assembles the file.

Does --partial leave an incomplete file in the destination? Until the copy finishes, yes. Use --partial-dir=.rsync-partial to hide the partial file in a temporary folder.

Does rsync encrypt traffic? When used with -e ssh, yes. A local copy does not cross the network.

Does rsync work across different file systems? Yes. It does not depend on the source file system; both sides only need to read and write normally.

Sources

bash
#!/usr/bin/env bash
# rsync in practice: copy, sync and resume.
# Run with no arguments for the demo in a temporary directory.
set -u

if ! command -v rsync >/dev/null 2>&1; then
    echo "rsync not found; install rsync to run this script"
    exit 0
fi

W=$(mktemp -d)
cd "$W"

echo "=== 1. initial copy ==="
mkdir -p source destination
printf 'line 1\nline 2\nline 3\n' > source/file.txt
rsync -a source/ destination/
echo "destination:"; ls destination

echo "=== 2. sync with --delete ==="
printf 'line 1 changed\nline 2\nline 3\n' > source/file.txt
printf 'leftover\n' > destination/extra.txt
rsync -avn --delete source/ destination/
rsync -a --delete source/ destination/
echo "after sync:"; ls destination

echo "=== 3. resume with --partial ==="
head -c 6291456 /dev/urandom > source/big.bin 2>/dev/null || true
if [ -s source/big.bin ]; then
    timeout 1s rsync -a --partial --progress --bwlimit=2048 source/big.bin destination/ 2>/dev/null || true
    rsync -a --partial --progress source/big.bin destination/ 2>/dev/null || true
    cmp source/big.bin destination/big.bin && echo "file complete and identical"
fi

echo "=== 4. remote recipe (not run) ==="
echo 'rsync -a --partial -e "ssh -i ~/.ssh/key" user@server:/data/ ./local/'

rm -rf "$W"
echo "done"

Read next

// By e-mail

Posts published here also go out by e-mail. Delivery has not started yet: whoever leaves an address now joins the first batch.

I store only your e-mail, the date and the record of this consent. No cookies, no trackers, nothing shared with third parties. Details in the privacy policy.