Subject: bug#68989: closed (Re: bug#68989: grep -m[2+] > /dev/null)

From: [email-masked] (GNU bug Tracking System)
Date: Fri, 09 Feb 2024 09:09:02 +0000

Your bug report

#68989: grep -m[2+] > /dev/null

which was filed against the grep package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
68989: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=68989
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#68989: grep -m[2+] > /dev/null
From: Paul Eggert <[email-masked]>
To: Grisha Levit <[email-masked]>
Cc: [email-masked]
Date: Fri, 9 Feb 2024 01:08:24 -0800
List-Id: <debbugs-submit.debbugs.gnu.org>

Thanks for the bug report. I installed the attached patch; please give 
it a try.

From b9a8047099d2388c15e6ad39e7b8c91c6633096c Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Fri, 9 Feb 2024 01:06:49 -0800
Subject: [PATCH] =?UTF-8?q?grep:=20fix=20=E2=80=98grep=20-m2=20pattern=20<?=
 =?UTF-8?q?file=20>/dev/null=E2=80=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Grisha Levit <https://bugs.gnu.org/68989>.
* src/grep.c (grep, main): Don’t set done_on_match if -m is used.
* tests/max-count-overread: Add a test case.
---
 NEWS                     | 3 +++
 src/grep.c               | 9 +++++++--
 tests/max-count-overread | 6 ++++++
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index bc487ce..4294fc6 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ GNU grep NEWS                                    -*- outline -*-
     1
   [bug introduced in grep 3.11]
 
+  -mN where 1 < N no longer mistakenly lseeks to end of input merely
+  because standard output is /dev/null.
+
 ** Changes in behavior
 
   On Windows platforms and on AIX in 32-bit mode, grep now supports
diff --git a/src/grep.c b/src/grep.c
index dab3be7..1256dfd 100644
--- a/src/grep.c
+++ b/src/grep.c
@@ -1558,7 +1558,11 @@ grep (int fd, struct stat const *st, bool *ineof)
           if (binary_files == WITHOUT_MATCH_BINARY_FILES)
             return 0;
           if (!count_matches)
-            done_on_match = out_quiet = true;
+            {
+              out_quiet = true;
+              if (max_count == INTMAX_MAX)
+                done_on_match = true;
+            }
           nlines_first_null = nlines;
           nul_zapper = eol;
           skip_nuls = skip_empty_lines;
@@ -2897,7 +2901,8 @@ main (int argc, char **argv)
   if ((exit_on_match | dev_null_output) || list_files != LISTFILES_NONE)
     {
       count_matches = false;
-      done_on_match = true;
+      if (max_count == INTMAX_MAX)
+        done_on_match = true;
     }
   out_quiet = count_matches | done_on_match;
 
diff --git a/tests/max-count-overread b/tests/max-count-overread
index 23c45cb..f829cc5 100755
--- a/tests/max-count-overread
+++ b/tests/max-count-overread
@@ -12,4 +12,10 @@ echo x > exp || framework_failure_
 yes x | timeout 10 grep -m1 x > out || fail=1
 compare exp out || fail=1
 
+# Make sure -m2 stops reading even when output is /dev/null.
+# In grep 3.11, it would continue reading.
+printf 'x\nx\nx\n' >in || framework_failure
+(grep -m2 x >/dev/null && head -n1) <in >out || fail=1
+compare exp out || fail=1
+
 Exit $fail
-- 
2.40.1

Subject: grep -m[2+] > /dev/null
From: Grisha Levit <[email-masked]>
To: [email-masked]
Date: Thu, 8 Feb 2024 03:37:24 -0500
List-Id: <debbugs-submit.debbugs.gnu.org>

This example file will require multiple reads:

$ printf '%07d\n' {0..98304} > txt

When limiting the match count to 1, the input offset is correctly restored
before grep exits,  no matter the output:

$ { grep -m1 . >/dev/zero; head -n1; } < txt
0000001
$ { grep -m1 . >/dev/null; head -n1; } < txt
0000001

If the count is 2 or higher, this also works, unless the output is being
discarded to /dev/null -- in this case not only is the input offset not
restored, but the entire file is consumed:

$ { grep -m2 . >/dev/zero; head -n1; } < txt
0000002
$ { grep -m2 . >/dev/null; head -n1; } < txt
$