Skip to content

grep: let the last matching --include or --exclude decide - #146

Merged
sylvestre merged 2 commits into
uutils:mainfrom
jayhemnani9910:include-exclude-order
Oct 24, 2026
Merged

sylvestre merged 2 commits into
uutils:mainfrom
jayhemnani9910:include-exclude-order

Conversation

@jayhemnani9910

Copy link
Copy Markdown
Contributor

--include and --exclude are kept as two separate sets: a file is skipped when any --exclude matches it or no --include does, whatever the order. GNU grep goes by order. Its man page: "If contradictory --include and --exclude options are given, the last matching one wins. If no --include or --exclude options match, a file is included unless the first such option is --include." So mixing them gives different files:

$ ls tree
a.txt  b.log
$ ./target/debug/grep -r -l --exclude='a*' --include='*.txt' foo tree
$ /usr/bin/grep -r -l --exclude='a*' --include='*.txt' foo tree    # GNU grep 3.12
tree/a.txt
tree/b.log

a.txt matches both, and the --include comes last. b.log matches neither, and the first pattern is an --exclude. --exclude=zz --include='*.txt' has the same problem: GNU keeps b.log, and this skips it.

The patterns now go into one list in command-line order (from clap's indices). --exclude-from patterns sit at the position of that option. GlobSet stays for --exclude-dir, and its is_empty goes since nothing uses it anymore.

Tests: recursive_include_exclude_last_match_wins covers both orders above and an --include followed by --exclude-from. It fails on main. The existing include/exclude tests pass unchanged. cargo test: 116 passed (115 on main), clippy and rustfmt clean. I compared 12 include/exclude/exclude-from orderings with GNU grep 3.12 under -r -l, and they all give the same files now.

--include and --exclude were two separate sets: a file was skipped when
any --exclude matched or no --include did, whatever the order. GNU grep
applies them in the order given: the last pattern that matches a name
decides, and a name that matches none is skipped only when the first
pattern is an --include. So "--exclude=a* --include=*.txt" searched
nothing where GNU searches a.txt and every file that matches neither.

Keep the patterns in one list in command-line order, with --exclude-from
patterns at the position of that option.
Copilot AI balanced review requested due to automatic review settings October 20, 2026 05:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@codspeed

codspeed Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 10 untouched benchmarks
⏩ 17 skipped benchmarks1


Comparing jayhemnani9910:include-exclude-order (61f6533) with main (01fb6c3)

Open in CodSpeed

Footnotes

  1. 17 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

Comment thread src/lib.rs
GlobSet now keeps whether each pattern is an include or an exclude, so
FileGlobs and its copy of add() go away. --exclude-dir adds its patterns
as excludes, which skips the same directories as before.
Copilot AI balanced review requested due to automatic review settings October 20, 2026 11:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@jayhemnani9910

Copy link
Copy Markdown
Contributor Author

Thanks, went with changing GlobSet. Pushed 61f6533: GlobSet keeps whether each pattern is an include or an exclude, so FileGlobs and its copy of add are gone. --exclude-dir adds its patterns as excludes and skips the same directories as before. Checked --exclude-dir and mixed --include/--exclude against GNU grep 3.12 on a small tree, same output.

@sylvestre
sylvestre merged commit 254de2f into uutils:main Oct 24, 2026
27 of 28 checks passed
@sylvestre

Copy link
Copy Markdown
Contributor

Thanks for your PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants