feat(grep): support -f/--file to read patterns from file (#327)
* fix(search-engine): group alternation inside -x line anchors `lineRegexp` wrapped the pattern as `^PATTERN$`, which anchors only the outer alternatives when PATTERN contains a top-level `|`: `a|b` became `^a|b$` (i.e. "starts with a" OR "ends with b") instead of "the whole line is a or b". Wrap in a non-capturing group, mirroring what the -w wrapper already does. Only observable once grep can produce multi-alternative patterns, which `grep -f` does. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DayCPuYZEmv4VszJXTHT3 Signed-off-by: Lars Trieloff <lars@trieloff.net> * feat(grep): support -f/--file to read patterns from file Adds GNU-compatible `-f FILE` / `--file=FILE`: patterns are read from FILE, one per line, and OR-combine with `-e` patterns and with each other. Forms accepted: `-f FILE`, `-fFILE`, `-vxf FILE`, `-vxfFILE`, `--file=FILE`, `--file FILE`, and `-f -` (patterns from stdin, which then leaves nothing to search on stdin). GNU edge cases matched (verified against GNU grep 3.12): - Empty pattern lines are real patterns that match every line; with -x they anchor to `^$` and match only blank lines. - A pattern file's trailing newline terminates the last pattern rather than introducing an empty one; a `-e` operand's trailing newline does introduce one. - An empty pattern file contributes no patterns. When the whole pattern list ends up empty, grep selects nothing and short-circuits: no output, no per-file `-c` counts, no "No such file or directory" diagnostics for the input files, exit 1. `-v` still selects every line, and `-L` still visits the files. - A missing or unreadable pattern file is reported as `grep: FILE: No such file or directory` (or `Is a directory`) with exit 2, before any input file is searched. An empty file name reports `grep: : No such file or directory` rather than resolving against the cwd. - stdin is a stream, so only the first `-f -` reads it; a repeated `-f -` hits EOF and contributes no patterns. - `-P` refuses more than one distinct pattern, as GNU's PCRE backend does. - `PATTERNS` operands are newline-separated lists, so a positional or `-e` pattern containing newlines is split into individual patterns too. Alternatives are joined textually, so each pattern is compiled on its own first (except for `-F`, whose patterns are escaped): otherwise a malformed pattern swallows the separator and silently absorbs its neighbour, e.g. `a\` + `banana` compiling as the literal `a|banana`. The number of patterns read from files is bounded by `maxArrayElements`. Unskips five busybox grep spec tests that were blocked on -f and on newline-delimited patterns. Closes #322. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DayCPuYZEmv4VszJXTHT3 Signed-off-by: Lars Trieloff <lars@trieloff.net> --------- Signed-off-by: Lars Trieloff <lars@trieloff.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
L
Lars Trieloff committed
eaedb5bc34cffd2077b88bb1ccc48ea7e0545a48
Parent: 65dafd5
Committed by GitHub <noreply@github.com>
on 8/6/2026, 2:03:54 AM