glob
exclude pattern
file matching
wildcard
programming

glob exclude pattern

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

There is no single universal "glob exclude syntax" that works everywhere. Basic globbing describes what to include, and exclusion is usually added by the tool, shell, or library that interprets the pattern.

Start with the important distinction

People often treat "glob" as one feature, but there are several related systems:

  • shell globbing in Bash or Zsh
  • library globbing in Python, Node.js, Go, and other languages
  • ignore-file syntax such as .gitignore
  • build-tool or test-runner pattern engines

They overlap, but they are not identical. A pattern that excludes files in one system may be invalid or behave differently in another.

That is why the first question should be: which glob engine are you using.

The common pattern: include plus ignore list

Most modern libraries handle exclusion by taking one or more include patterns and a separate ignore or exclude list.

In Node.js, a library such as fast-glob commonly works like this:

javascript
1const fg = require("fast-glob");
2
3async function run() {
4  const files = await fg(["src/**/*.js"], {
5    ignore: ["src/**/*.test.js", "src/vendor/**"]
6  });
7
8  console.log(files);
9}
10
11run().catch(console.error);

This is often the cleanest mental model:

  • include what you want broadly
  • subtract unwanted paths with explicit ignore patterns

Many tools built on glob engines use the same structure even if the option name is exclude, ignore, or negate.

Python usually filters after matching

Python's standard glob module is intentionally simple. It matches includes, but it does not have a first-class exclude parameter in the same style as some Node libraries. A common solution is to collect matches and filter them yourself.

python
1from glob import glob
2from pathlib import Path
3
4files = glob("src/**/*.py", recursive=True)
5filtered = [
6    path for path in files
7    if "tests" not in Path(path).parts and not path.endswith("_generated.py")
8]
9
10print(filtered)

That may look less elegant than a single pattern, but it is explicit and easy to debug. For many scripts, this is better than forcing shell-specific pattern tricks into Python code.

Shell negation is tool-specific

Some shells support exclusion-like constructs, but only when specific features are enabled.

In Bash, extended globbing allows negation with !(pattern), but you must enable it first.

bash
shopt -s extglob
printf '%s\n' !(node_modules)

Even then, the behavior is shell-specific and does not automatically give you recursive exclusion semantics like "all JavaScript files except anything under vendor." That is why shell negation is useful for interactive commands but not a good universal answer.

Zsh and Bash also differ in details, so patterns copied from one shell may not behave the same in another.

A lot of confusion comes from .gitignore. It supports negation with a leading !, but .gitignore is not the same thing as general glob syntax.

Example:

gitignore
*.log
!important.log
build/

That means:

  • ignore all .log files
  • re-include important.log
  • ignore the build directory

This is powerful, but it belongs to Git's ignore engine. Do not assume the same negation rules exist in your programming language's glob library.

A practical strategy for exclusion

If you need robust matching, use a two-step approach:

  1. define the broad include pattern
  2. exclude paths with explicit ignore rules or post-filtering

For example, if you want all Markdown files under docs except generated output and vendor content, think in terms of sets:

  • include: docs/**/*.md
  • exclude: docs/generated/**, docs/vendor/**

That approach is portable across many tools because even when the exact syntax changes, the concept stays stable.

When recursive matching is involved

Recursive ** patterns are another source of confusion. Some engines support **, some do not, and some only support it in special modes. If your exclude rule relies on recursion, verify that the engine supports the same interpretation for both include and exclude patterns.

This matters because a rule like vendor/** may work exactly as expected in one library and fail silently in another if recursion support differs.

Common Pitfalls

A common mistake is assuming that glob syntax is standardized across shells, libraries, and ignore files. It is not.

Another mistake is trying to cram complex exclusion logic into one clever pattern. Include plus ignore is usually easier to read and maintain.

A third mistake is copying .gitignore negation syntax into a program that uses a different glob engine.

Summary

  • There is no universal exclude operator for all glob implementations.
  • Many tools solve exclusion with include patterns plus a separate ignore list.
  • Python's standard glob often requires explicit post-filtering.
  • Shell negation such as Bash extglob is real, but it is shell-specific.
  • Always verify the exact glob engine before relying on exclusion syntax.

Course illustration
Course illustration

All Rights Reserved.