Skip to content

/commands/tar/tar-exclude

tar --exclude: leave files and directories out of an archive

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · tar (GNU tar) 1.35updated
tool
tar
versions
GNU tar 1.30+, bsdtar 3.x
os
linux, macos, windows

tar -czf backup.tar.gz --exclude=node_modules --exclude='*.log' project archives project without any node_modules directory and without .log files. Each --exclude takes one shell-style pattern; quote patterns that contain * so the shell does not expand them. With GNU tar, put the --exclude options before the paths: options after the paths only apply to arguments that follow them. For long lists, write the patterns in a file and pass it with --exclude-from=FILE (-X FILE).

Example

bash
mkdir -p proj/src proj/node_modules/lib proj/.git
touch proj/src/a.js proj/node_modules/lib/i.js proj/.git/HEAD proj/app.log proj/README.md
tar -czf proj.tar.gz --exclude=node_modules --exclude='*.log' --exclude=.git proj
tar -tzf proj.tar.gz | sort

Output

proj/
proj/README.md
proj/src/
proj/src/a.js

The archive keeps README.md and src/a.js. A pattern without a slash, such as node_modules, matches a file or directory of that name at any depth, and an excluded directory is skipped with everything below it.

Exclude after the paths

bash
mkdir -p proj/node_modules/lib
touch proj/node_modules/lib/i.js proj/index.js
tar -czf late.tar.gz proj --exclude=node_modules

Output · exit 2

tar: The following options were used after non-option arguments.  These options are positional and affect only arguments that follow them.  Please, rearrange them properly.
tar: --exclude ‘node_modules’ has no effect
tar: Exiting with failure status due to previous errors

GNU tar 1.35 refuses to let a trailing --exclude pass silently: it prints the warning above, writes the archive with node_modules and exits with status 2. Older GNU tar releases and bsdtar accept the options in any order, which is why scripts copied from elsewhere may still put them at the end.

Pattern forms

OptionLeaves out
--exclude=node_modulesAny file or directory named node_modules, at any depth
--exclude='*.log'Every name ending in .log
--exclude='proj/cache'Any member path ending in proj/cache (GNU patterns are unanchored by default)
--exclude='proj/cache/*'The contents of proj/cache, keeping the empty directory
--exclude-from=.tarignore / -X FILEOne pattern per line from a file
--exclude-vcsVersion control directories such as .git, .svn, .hg (GNU)
--exclude-vcs-ignoresPatterns read from .gitignore and similar ignore files (GNU)
--exclude-cachesDirectories marked with a CACHEDIR.TAG file, except the tag (GNU)
--exclude-tag=FILEDirectories that contain FILE, except FILE itself (GNU)

Pitfalls

  • Patterns are unanchored in GNU tar. --exclude='sub/b.log' also matches proj/sub/b.log, and archiving ./proj instead of proj still matches proj/node_modules. Add --anchored before the pattern when it must match from the start of the member name only.
  • Trailing slashes. --exclude=node_modules/ does not match in GNU tar, because member names of directories are compared without the slash. Write the name without it.
  • Wildcards and slashes. In GNU tar, * in an exclude pattern also matches / by default, so --exclude='proj/*.log' excludes log files in subdirectories as well.
  • bsdtar (macOS, Windows tar.exe) supports --exclude and -X, but not the --exclude-vcs family.

Confirm it worked

List the result and search it: tar -tzf proj.tar.gz | grep node_modules should print nothing. Compare the size with an archive made without the excludes to see how much was left out.

FAQ

Why does my --exclude have no effect?

Usually because it comes after the paths to archive. GNU tar 1.35 treats --exclude as positional and warns that it has no effect when nothing follows it. Put every --exclude before the directory names. The other common cause is a pattern with a trailing slash, which does not match the member names tar stores.

How do I exclude a directory but keep the directory itself in the archive?

Exclude its contents instead of its name, for example --exclude='proj/cache/*'. The empty cache directory is then stored, which helps when the application expects it to exist after extraction.

Can I exclude files when extracting?

Yes. --exclude also works with -x, as in tar -xzf backup.tar.gz --exclude='*.log'. The pattern is matched against the member names stored in the archive.

Sources