DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

Excluding a type of files in rsync

— ny_wk

Excluding a type of files in rsync

To exclude a file type in rsync, add the --exclude option with a glob pattern such as --exclude='*.txt' so matching files are skipped during the transfer. This guide shows you exactly how to sync two servers while leaving out one or more file extensions, why the pattern syntax behaves the way it does, and how to verify the result so nothing slips through.

Copying data between machines is one of the most common tasks a Linux administrator handles, and rsync is the standard tool for the job because it transfers only the differences between source and destination. Often, though, you do not want a clean one-to-one mirror — you want to exclude a file type in rsync, for example skipping noisy log files, temporary .tmp files, or, in our scenario, every .txt file in a data directory. The mechanism that makes this possible is rsync's filter system, and once you understand it you can shape almost any transfer.

The scenario: two servers, two file types, one exclusion

We have two machines named unixmate1 (the source) and unixmate2 (the destination). On unixmate1 there is a directory, /unidb, that holds two different formats of files: .data files (which we want) and .txt files (which we do not). The goal is to sync /unidb from unixmate1 to unixmate2 while excluding every .txt file from the transfer.

This is a textbook use case for selective synchronization: the same source directory needs to land on another host, but a subset of its contents must be filtered out on the fly without first having to delete or move those files manually.

Prerequisites

  • rsync installed on both servers. Confirm with rsync --version. Install it with sudo apt install rsync on Debian/Ubuntu or sudo dnf install rsync on RHEL/Fedora.
  • SSH access from unixmate1 to unixmate2 (rsync tunnels over SSH by default for remote transfers). Key-based authentication is strongly recommended over passwords.
  • Read permission on the source files and write permission on the destination path.

Step-by-step: how to exclude a file type in rsync

We will build up the transfer in three deliberate stages — create test data, prove a normal sync works, then re-run with the exclusion — so you can see precisely what the --exclude option changes.

  1. Create a test directory with mixed file types on unixmate1.
    Make the directory and drop in a few files of each extension so the difference is visible:
    mkdir -p /unidb
    cd /unidb
    touch file1.data file2.data file3.data
    touch notes1.txt notes2.txt readme.txt
    Confirm the contents with ls -l /unidb. You should see three .data files and three .txt files.
  2. Run a normal rsync and verify everything transfers.
    First, prove the baseline works without any filtering:
    rsync -avz /unidb/ user@unixmate2:/unidb/
    On unixmate2, run ls -l /unidb. All six files (both .data and .txt) should now be present. This confirms connectivity, permissions, and the path are correct before you add complexity.
  3. Clear the destination so the re-sync is unambiguous.
    To make the next test clean, remove the copied directory on unixmate2:
    rm -rf /unidb/*
    Run this on the destination host. Deleting only the contents (not the directory itself) keeps ownership and permissions intact.
  4. Re-sync with the exclusion option.
    Now add --exclude with the pattern for the extension you want to skip:
    rsync -avz --exclude='*.txt' /unidb/ user@unixmate2:/unidb/
    The single quotes are important — they stop your shell from expanding *.txt before rsync ever sees it. rsync needs the literal pattern.
  5. Confirm the result on unixmate2.
    ls -l /unidb
    You should now see only the three .data files. Every .txt file was filtered out of the transfer.

Why the trailing slash and the quotes matter

Two small details cause the majority of rsync surprises, and both appear in the commands above.

The trailing slash on the source (/unidb/) tells rsync to copy the contents of the directory into the destination. Without it (/unidb), rsync copies the directory itself, creating /unidb/unidb/ on the destination. Pick one convention and stay consistent. The destination slash is harmless either way but is good practice for clarity.

Quoting the pattern matters because *.txt is a glob that your shell will try to expand against the current directory before running rsync. If files matching that pattern happen to exist in your working directory, the shell substitutes their names and rsync receives the wrong argument. Wrapping the pattern in single quotes — --exclude='*.txt' — passes it through untouched so rsync's own pattern engine evaluates it.

Excluding more than one file type at once

Real environments rarely have just one extension to skip. rsync lets you repeat the option as many times as needed:

rsync -avz --exclude='*.txt' --exclude='*.log' --exclude='*.tmp' /unidb/ user@unixmate2:/unidb/

When the exclude list grows long, move it into an exclude file — one pattern per line — and reference it with --exclude-from. This keeps commands readable and lets you version-control the rules:

cat exclude-rules.txt

*.txt
*.log
*.tmp
cache/

rsync -avz --exclude-from='exclude-rules.txt' /unidb/ user@unixmate2:/unidb/

A trailing slash inside the rules (such as cache/) restricts the match to directories only, which is handy when a name could be either a file or a folder.

Understanding rsync filter patterns

The --exclude option uses rsync's own pattern matching, which is similar to shell globbing but has its own rules worth knowing. This is where most subtle mistakes happen.

PatternWhat it matches
*.txtAny file ending in .txt, in any directory of the transfer
/tempAn item named temp at the top level of the transfer root only (the leading slash anchors it)
temp/Any directory named temp, at any depth, and everything inside it
**/*.bak.bak files at any depth (** crosses directory boundaries)
?Exactly one character (not a path separator)

The key thing to internalize: a single * does not cross a / boundary, while ** does. A leading / anchors the pattern to the root of the transfer rather than matching at every level.

Combining include and exclude rules

Filters are evaluated in order, and the first matching rule wins. That ordering lets you exclude broadly but rescue specific files. For example, to skip every .txt file except one named important.txt, place the include rule first:

rsync -avz --include='important.txt' --exclude='*.txt' /unidb/ user@unixmate2:/unidb/

Because rsync reads rules top to bottom and stops at the first match, important.txt is caught by the include before it ever reaches the exclude. Reverse the order and the include would never fire.

Common pitfalls when you exclude a file type in rsync

  • Forgetting to quote the pattern. Unquoted *.txt gets expanded by your shell. Always use --exclude='*.txt' with single quotes.
  • Adding a path to the pattern by accident. Writing --exclude='/unidb/*.txt' usually matches nothing, because rsync patterns are relative to the transfer root, not the absolute filesystem path. Use --exclude='*.txt'.
  • Expecting --exclude to delete files already on the destination. Excluding only prevents transferring a file; it does not remove a copy that is already there. Files that were transferred in a previous run will remain unless you also use --delete-excluded.
  • Misordering include/exclude rules. First match wins. An include must come before the broader exclude that would otherwise swallow it.
  • Trusting the run without a dry run. On production data, always preview first (next section) so a stray pattern does not silently drop files you needed.
  • Case sensitivity. rsync patterns are case-sensitive: *.txt will not match NOTES.TXT. List both cases if your data is mixed.

Verification: confirm the exclusion actually worked

Never assume a transfer did what you intended — verify it. There are three good ways, from safest to most thorough.

  1. Dry run before committing. Add --dry-run (or -n) to see exactly what rsync would do without writing anything:
    rsync -avzn --exclude='*.txt' /unidb/ user@unixmate2:/unidb/
    The output lists each file rsync plans to send. No .txt file should appear. This is the single most valuable habit when working with filters on real data.
  2. List the destination after the real run.
    ssh user@unixmate2 'ls -l /unidb'
    Only the intended file types should be present.
  3. Explicitly count the excluded type on the destination.
    ssh user@unixmate2 'find /unidb -name "*.txt" | wc -l'
    A result of 0 proves no .txt files made it across. Compare with the source count, find /unidb -name "*.txt" | wc -l, to confirm they were genuinely excluded rather than simply absent.

A practical, production-ready command

Putting the useful options together, a robust selective sync over SSH looks like this:

rsync -avz --progress --exclude='*.txt' -e 'ssh -p 22' /unidb/ user@unixmate2:/unidb/

Here is what each flag does:

  • -aarchive mode: recurse and preserve permissions, timestamps, symlinks, and ownership.
  • -vverbose, so you see what is transferred.
  • -zcompress data in transit (helpful over slow links, less useful on a fast LAN or for already-compressed files).
  • --progress — show a live progress bar per file.
  • --exclude='*.txt' — the filter that skips the unwanted file type.
  • -e 'ssh -p 22' — specify the remote shell and port explicitly (change the port if your SSH listens elsewhere).

If you also want the destination to become an exact mirror — deleting files that no longer exist on the source — add --delete. Combine it with --delete-excluded if you want previously-copied excluded files purged from the destination too. Both are powerful and irreversible, so test them with --dry-run first.

Key Takeaways

  • Use --exclude='*.ext' to exclude a file type in rsync, and always quote the pattern so your shell does not expand it.
  • rsync patterns are relative to the transfer root, not the absolute path; a single * does not cross /, but ** does.
  • Repeat --exclude for multiple types, or use --exclude-from=file for a maintainable rule list; combine with --include (placed first) to rescue specific files.
  • --exclude only prevents transferring; it does not remove files already on the destination unless you add --delete-excluded.
  • Always preview with --dry-run and verify on the destination with find ... -name '*.ext' | wc -l before trusting a real run.

Frequently Asked Questions

How do I exclude a directory instead of a file type in rsync?

Use the directory name with a trailing slash, for example --exclude='cache/' to skip any folder named cache and its contents. To anchor it to the top level only, add a leading slash: --exclude='/cache/'. Combine directory and file-type excludes freely in one command.

Does rsync --exclude delete files already on the destination?

No. By itself, --exclude only prevents matching files from being copied. Files transferred in an earlier run stay on the destination. To remove excluded files that already exist there, add --delete-excluded, and test it with --dry-run first because deletion is irreversible.

What is the difference between --exclude and .gitignore-style patterns?

They are similar but not identical. rsync filter rules are evaluated in order with first-match-wins semantics, support --include rules and per-directory .rsync-filter files, and treat a leading slash as an anchor to the transfer root. Test patterns with --dry-run rather than assuming Git behavior.

Why is my exclude pattern being ignored?

The two most common causes are an unquoted pattern that the shell expanded, and a pattern written with an absolute path like /full/path/*.txt instead of a root-relative one like *.txt. Quote the pattern and keep it relative to the transfer root. If you mix include and exclude rules, check the order — the first matching rule wins.

For more Linux and sysadmin walkthroughs, subscribe to our YouTube channel @explorenystream.