Published on

TIL: Trailing slashes in tar exclude patterns silently disable directory matching

TIL: Trailing slashes in tar exclude patterns silently disable directory matching
Authors

A backup script created tar archives of an application folder before a release. It was supposed to exclude the local database directory and temporary state:

tar -czf backup.tar.gz --exclude='db/' app/

When I checked the archive contents, the entire database was inside:

tar -tf backup.tar.gz | grep '^app/db'
# app/db/
# app/db/data.sqlite

The issue was the trailing slash in --exclude='db/'.

When tar scans files and directories, each path it inspects arrives without a trailing slash. When tar visits app/db, it compares app/db to the pattern db/. The pattern requires a slash at the end, so the string comparison fails.

Because app/db did not match the exclude rule, tar enters the directory. Next it inspects app/db/data.sqlite. That path has characters after the slash, so it fails to match db/ as well. As a result, tar excludes nothing and bundles the whole database into the archive.

You can verify the behavior in one test:

mkdir -p test/db && touch test/db/data.sqlite test/app.js

# Fails to exclude:
tar -cf - --exclude='db/' test | tar -tf -
# test/db/
# test/db/data.sqlite

# Correctly excludes:
tar -cf - --exclude='db' test | tar -tf -
# test/
# test/app.js

Removing the trailing slash allows tar to match the directory name directly. tar skips test/db immediately and never traverses its child files. If you only want to exclude directory contents while preserving the empty directory, use db/* instead.

When writing tar exclude patterns, never add a trailing slash to a directory path.