Greetings! The attached patch add a `--pipe` option to grep. When used, grep only exits with with nonzero status on error. In particular, it doesn't signal "match" / "no match" through the exit code.
Here's an example using Bash: # enable automatic error handling set -eo pipefail # grep for issues in a logfile to produce a report cat logfile | grep issue | sort --unique If grep doesn't find "issue" in its input (which is not an error, obviously), it exits with status 1. Bash interprets this nonzero exit code as an error and terminates with an error itself. In order to fix that bug in the above script, you currently have to replace `grep ...` with `grep ... || [ $? = 1 ]`, which is not really readable. As alternative, I've implemented a `--pipe` option, which only returns nonzero on actual errors, but not when there is no match. This is a bit of a complementary option to `--quiet`. Open tasks here: * FSF paperwork is not finished, so obviously the patch can't be applied yet. * Should I add a `-p` to complement the long `--pipe`? * Should I call it `--pipe` at all? The other alternative I came up with was `--filter`. I don't really like either of them very much. Cheers! Uli
>From 02f00ec50e820b9320af66ee7bb47bab36184f96 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt <ulrich.eckha...@base-42.de> Date: Mon, 14 Feb 2022 19:23:10 +0100 Subject: [PATCH 1/4] grep: implement `--pipe` option * src/grep.c: Implement `--pipe` option, which does not indicate matches or lack thereof in the exit code but only filters the input into the output. --- src/grep.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/grep.c b/src/grep.c index 9c933e4..2260d7d 100644 --- a/src/grep.c +++ b/src/grep.c @@ -498,7 +498,8 @@ enum INCLUDE_OPTION, LINE_BUFFERED_OPTION, LABEL_OPTION, - NO_IGNORE_CASE_OPTION + NO_IGNORE_CASE_OPTION, + PIPE_OPTION }; /* Long options equivalences. */ @@ -543,6 +544,7 @@ static struct option const long_options[] = {"null", no_argument, NULL, 'Z'}, {"null-data", no_argument, NULL, 'z'}, {"only-matching", no_argument, NULL, 'o'}, + {"pipe", no_argument, NULL, PIPE_OPTION}, {"quiet", no_argument, NULL, 'q'}, {"recursive", no_argument, NULL, 'r'}, {"dereference-recursive", no_argument, NULL, 'R'}, @@ -1078,6 +1080,7 @@ static enum static int out_file; static int filename_mask; /* If zero, output nulls after filenames. */ +static bool out_pipe; /* --pipe: Don't set exit status depending on match. */ static bool out_quiet; /* Suppress all normal output. */ static bool out_invert; /* Print nonmatching stuff. */ static bool out_line; /* Print line numbers. */ @@ -2017,6 +2020,7 @@ Output control:\n\ ")); printf (_("\ -o, --only-matching show only nonempty parts of lines that match\n\ + --pipe only filter, do not set exit value depending on found matches\n\ -q, --quiet, --silent suppress all normal output\n\ --binary-files=TYPE assume that binary files are TYPE;\n\ TYPE is 'binary', 'text', or 'without-match'\n\ @@ -2698,6 +2702,10 @@ main (int argc, char **argv) only_matching = true; break; + case PIPE_OPTION: + out_pipe = true; + break; + case 'q': exit_on_match = true; exit_failure = 0; @@ -3008,5 +3016,9 @@ main (int argc, char **argv) status &= grep_command_line_arg (*files++); while (*files != NULL); - return errseen ? EXIT_TROUBLE : status; + if (errseen) + return EXIT_TROUBLE; + if (out_pipe) + return EXIT_SUCCESS; + return status; } -- 2.32.0 >From e930e55fd34f02bd9959148c1d43a3fe521e2169 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt <ulrich.eckha...@base-42.de> Date: Mon, 14 Feb 2022 21:36:39 +0100 Subject: [PATCH 2/4] tests: add tests for --pipe * tests/pipe: Add new test file exercising the `--pipe` option. * tests/Makefile.am: Register new test file. --- tests/Makefile.am | 1 + tests/pipe | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100755 tests/pipe diff --git a/tests/Makefile.am b/tests/Makefile.am index a211cb6..ae8ffc8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -148,6 +148,7 @@ TESTS = \ pcre-w \ pcre-wx-backref \ pcre-z \ + pipe \ posix-bracket \ prefix-of-multibyte \ proc \ diff --git a/tests/pipe b/tests/pipe new file mode 100755 index 0000000..9c789bb --- /dev/null +++ b/tests/pipe @@ -0,0 +1,42 @@ +#!/bin/sh +# tests for --pipe commandline option +# A missing or found match does not influence the exit status. + +. "${srcdir=.}/init.sh" +path_prepend_ ../src + +require_timeout_ + +failures=0 + +# should return 0 even though it doesn't find a match in stdin +echo -n '' | LC_ALL=C timeout 10s grep --pipe abcd +if test $? -ne 0 ; then + echo 'Status: Wrong status code, test #1 failed' + failures=1 +fi + +# should return 0 even though it doesn't find a match in the input file +echo -n '' > in +LC_ALL=C timeout 10s grep --pipe abcd in +if test $? -ne 0 ; then + echo 'Status: Wrong status code, test #2 failed' + failures=1 +fi + +# should return 0 even though it doesn't find a match in stdin +echo -n '' | LC_ALL=C timeout 10s grep --invert-match --pipe abcd +if test $? -ne 0 ; then + echo 'Status: Wrong status code, test #3 failed' + failures=1 +fi + +# should return 0 even though it doesn't find a non-match in the input file +echo -n '' > in +LC_ALL=C timeout 10s grep --invert-match --pipe abcd in +if test $? -ne 0 ; then + echo 'Status: Wrong status code, test #4 failed' + failures=1 +fi + +Exit $failures -- 2.32.0 >From 7bcc7fb748be62bf87be15e5d1f78d54b6c10823 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt <ulrich.eckha...@base-42.de> Date: Tue, 15 Feb 2022 20:46:12 +0100 Subject: [PATCH 3/4] doc: update manpage * doc/grep.in.1: Add --pipe manpage documentation. --- doc/grep.in.1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/grep.in.1 b/doc/grep.in.1 index 372b892..89aa5fc 100644 --- a/doc/grep.in.1 +++ b/doc/grep.in.1 @@ -357,6 +357,14 @@ non-matching lines. Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line. .TP +.B \-\^\-pipe +For use in pipelines. Just apply the configured input filters but +don't set any exit status depending on found matches. Not matching +the search pattern is not always an error, so don't report it like +one. The use is shell scripting (e.g. Bash's `set -o pipefail`), +which otherwise requires explicitly checking for exit codes 0 or 1 +in the middle of a pipeline. +.TP .BR \-q ", " \-\^\-quiet ", " \-\^\-silent Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, @@ -971,7 +979,11 @@ or or .B \-\^\-silent is used and a line is selected, the exit status is 0 even if an error -occurred. +occurred. With the +.B \-\^\-pipe +option, the exit status is 2 when an error occurred and 0 otherwise. +Other @command{grep} implementations may exit with status greater than +2 on error. . .SH ENVIRONMENT The behavior of -- 2.32.0 >From 4fd80ac450dc2429dd03e803c9a8a729307ba069 Mon Sep 17 00:00:00 2001 From: Ulrich Eckhardt <ulrich.eckha...@base-42.de> Date: Tue, 15 Feb 2022 20:57:12 +0100 Subject: [PATCH 4/4] doc: update texinfo * doc/grep.texi: Add --pipe documentation. --- doc/grep.texi | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/grep.texi b/doc/grep.texi index 37ef839..b2a98bd 100644 --- a/doc/grep.texi +++ b/doc/grep.texi @@ -387,6 +387,16 @@ Output lines use the same delimiters as input, and delimiters are null bytes if @option{-z} (@option{--null-data}) is also used (@pxref{Other Options}). +@item --pipe +@opindex --pipe +@cindex --pipe +For use in pipelines. Just apply the configured input filters but +don't set any exit status depending on found matches. Not matching +the search pattern is not always an error, so don't report it like +one. The use is shell scripting (e.g. Bash's `set -o pipefail`), +which otherwise requires explicitly checking for exit codes 0 or 1 +in the middle of a pipeline. + @item -q @itemx --quiet @itemx --silent @@ -1093,8 +1103,9 @@ Normally the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if an error occurred. However, if the @option{-q} or @option{--quiet} or @option{--silent} option is used and a line is selected, the exit status is 0 even if an error -occurred. Other @command{grep} implementations may exit with status -greater than 2 on error. +occurred. With the @option{--pipe} option, the exit status is 2 +when an error occurred and 0 otherwise. Other @command{grep} +implementations may exit with status greater than 2 on error. @node grep Programs @section @command{grep} Programs -- 2.32.0