fix(grep): apply -m per file, as GNU does - #2487
Merged
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 634fdda | Commit Preview URL Branch Preview URL |
Sep 29 2026, 11:55 AM |
chaliy
force-pushed
the
claude/pensive-hypatia-yl92dr
branch
from
September 29, 2026 11:39
85c56ec to
2060150
Compare
GNU's -m NUM stops reading *each file* after NUM matching lines; the budget is per operand. Bashkit accumulated matches across operands and broke out of the file loop once the total was spent, so a file that used up the budget silenced every file after it. Verified against GNU grep 3.11: $ grep -m1 foo p.txt q.txt p.txt:foo1 q.txt:foo4 # bashkit stopped after p.txt $ grep -c -m1 foo p.txt q.txt p.txt:1 q.txt:1 # bashkit omitted this row entirely Same shape for -v. The per-file counter that drives output already existed (match_count), so the budget checks now read it instead of the cross-file total, and the total is gone along with the cross-file break. This removes the last divergence found while reviewing #2485. The 275-case differential sweep (-m0/-m1/-m2/-m5 x -q/-c/-l/-L/-v/-n/-o/-i/-H/-h x present, multiple, missing and mixed operands) now matches GNU grep 3.11 byte for byte: 33 divergent lines before #2485, 6 after it, 0 now. Two max_reached assignments became dead once the budget was per-file, since their break already leaves the loop. Removed, with a note that the flag now exists only so the -o closure can signal out of itself. Claude-Session: https://claude.ai/code/session_01DyKfW3rVZUrUKzrCLpurco
chaliy
force-pushed
the
claude/pensive-hypatia-yl92dr
branch
from
September 29, 2026 11:54
2060150 to
634fdda
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
GNU's
-m NUMstops reading each file after NUM matching lines — the budget is per operand. Bashkit accumulated matches across operands and broke out of the file loop once the total was spent, so a file that used up the budget silenced every file after it.The per-file counter that drives output already existed (
match_count), so the budget checks now read it instead of the cross-filetotal_matches, and that accumulator is gone along with the cross-file break.Why
Found while reviewing #2485. It was out of scope there — that PR is about
-m0operand handling, this is the accumulator — so it was flagged for follow-up rather than folded in. This is that follow-up, and it removes the last remaining divergence from GNU in the-mfamily.Before / After
Verified against GNU grep 3.11, with
p.txt=foo1 foo2 foo3andq.txt=foo4 foo5:grep -m1 foo p.txt q.txtp.txt:foo1q.txt:foo4p.txt:foo1grep -c -m1 foo p.txt q.txtp.txt:1q.txt:1p.txt:1grep -v -m1 foo v.txt q.txtv.txt:barThe
-ccase is the clearest symptom: a count row for the second operand simply disappeared, sogrep -cunder-msilently under-reported which files were searched at all.Differential sweep — 275 cases (
-m0/-m1/-m2/-m5×-q/-c/-l/-L/-v/-n/-o/-i/-H/-h× present, multiple, missing and mixed operands), byte-compared against GNU grep 3.11:Risk
-mbudget consults.-mwithout multiple operands is unaffected, and-Lkeeps the exemption added in fix(grep): skip operands for quiet zero match limit #2485. No existing test encoded the cumulative behaviour — all 63builtins::grepunit tests and 61 grep integration/spec tests passed unchanged before the new spec cases were added.max_reachedassignments became dead once the budget was per-file (theirbreakalready leaves the loop). Removed, with a note that the flag now exists only so the-oclosure can signal out of itself — caught byclippy -D warnings, not by hand.Checklist
-m1/-m2across two operands, one covering-cand-v. Each spec block gets a fresh VFS, so both create their own inputs.cargo fmt --check,cargo clippy --features http_client,ssh,sqlite -- -D warnings, 63 unit + 61 integration/spec tests all green.https://claude.ai/code/session_01DyKfW3rVZUrUKzrCLpurco
Generated by Claude Code