From d91845fd11f3656201ecfa480837f082f90ba649 Mon Sep 17 00:00:00 2001 From: MsfPablo Date: Tue, 18 Aug 2026 12:59:52 +0200 Subject: [PATCH] grep: don't short-circuit -v empty pattern under -x/-w --- src/lib.rs | 11 +++++++++-- tests/test_grep.rs | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2d05fda..5658611 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -445,8 +445,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } // An empty pattern matches every line; with `-v`, GNU grep selects no lines - // and exits as "no match" without reading any input files. - if invert_match && patterns.iter().any(|pattern| pattern.is_empty()) { + // and exits as "no match" without reading any input files. This does not + // hold under `-x` or `-w`, where an empty pattern matches only an empty + // line or an empty match at a word boundary, so the inversion still selects + // the remaining lines and the input has to be read. + if invert_match + && !word_regexp + && !line_regexp + && patterns.iter().any(|pattern| pattern.is_empty()) + { return Err(ExitCode::new(1)); } diff --git a/tests/test_grep.rs b/tests/test_grep.rs index b477329..f7a71ef 100644 --- a/tests/test_grep.rs +++ b/tests/test_grep.rs @@ -674,6 +674,30 @@ fn empty_pattern_matches_every_line() { .stdout_only("a\nb\nc\n"); } +#[test] +fn inverted_empty_pattern_does_not_short_circuit_under_x_or_w() { + // Under `-x` the empty pattern matches only an empty line, and under `-w` + // only an empty match at a word boundary, so `-v` still selects the rest. + let (_s, mut c) = ucmd(); + c.args(&["-e", "", "-x", "-v"]) + .pipe_in("abc\ndef\n") + .succeeds() + .stdout_only("abc\ndef\n"); + + let (_s, mut c) = ucmd(); + c.args(&["-e", "", "-w", "-v"]) + .pipe_in("abc\ndef\n") + .succeeds() + .stdout_only("abc\ndef\n"); + + // `-x` still drops the empty line itself. + let (_s, mut c) = ucmd(); + c.args(&["-e", "", "-x", "-v"]) + .pipe_in("abc\n\ndef\n") + .succeeds() + .stdout_only("abc\ndef\n"); +} + #[test] fn inverted_empty_pattern_short_circuits() { // grep short-circuits without reading stdin at all, so the harness's write