Package: grep;
Reported by: Alejandro Colomar <alx <at> kernel.org>
Date: 2025年10月30日 13:44:01 UTC
Severity: normal
To reply to this bug, email your comments to 79728 AT debbugs.gnu.org.
the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-grep <at> gnu.org:bug#79728; Package grep.
(2025年10月30日 13:44:02 GMT) Full text and rfc822 format available.Alejandro Colomar <alx <at> kernel.org>:bug-grep <at> gnu.org.
(2025年10月30日 13:44:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Alejandro Colomar <alx <at> kernel.org> To: bug-grep <at> gnu.org Subject: Flag to return 0 if no match Date: 2025年10月30日 14:42:29 +0100
[Message part 1 (text/plain, inline)]
Hi!
I'm working on a script around grep(1) which calls
set -Eeuo pipefail;
trap 'exit 2;' ERR;
...
| xargs grep regex;
I'd like to be able to return 2 on any errors, like grep(1) does, which
is why I'm using the trap(1). However, I need to workaround the fact
that grep(1) returns non-zero for no matches. What I'm doing at the
moment is
...
| {
xargs grep regex || true;
};
However, this also hides errors from xargs, which I'd like to keep.
Alternatively, I could use something like
...
| while read -r f; do
grep regex "$f" || true;
done;
However, the performance would drop to unusable levels (I experienced
a slow down of 100x in a quick test I did), so it's not an option.
Would you mind adding an option to coerce grep(1) to return 0 on zero
matches?
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es>
Use port 80 (that is, <...:80/>).
[signature.asc (application/pgp-signature, inline)]
bug-grep <at> gnu.org:bug#79728; Package grep.
(2025年10月30日 15:03:02 GMT) Full text and rfc822 format available.Message #8 received at 79728 <at> debbugs.gnu.org (full text, mbox):
From: "Dale R. Worley" <Dale.Worley <at> comcast.net> To: Alejandro Colomar <alx <at> kernel.org> Cc: 79728 <at> debbugs.gnu.org Subject: Re: bug#79728: Flag to return 0 if no match Date: 2025年10月30日 11:02:33 -0400
Of course, xargs grep regex is tricky to handle because you want grep to produce exit statuses that xargs will process to produce the exit status you want. I think this will get the effect you want: ... | xargs bash -c "grep $regex ; [[ \$? -le 1 ]]' and it runs grep no more times than "xargs grep" will. Dale
bug-grep <at> gnu.org:bug#79728; Package grep.
(2025年10月30日 15:12:02 GMT) Full text and rfc822 format available.Message #11 received at 79728 <at> debbugs.gnu.org (full text, mbox):
From: Alejandro Colomar <alx <at> kernel.org> To: "Dale R. Worley" <Dale.Worley <at> comcast.net> Cc: 79728 <at> debbugs.gnu.org Subject: Re: bug#79728: Flag to return 0 if no match Date: 2025年10月30日 16:11:08 +0100
[Message part 1 (text/plain, inline)]
Hi Dale, On Thu, Oct 30, 2025 at 11:02:33AM -0400, Dale R. Worley wrote: > Of course, > > xargs grep regex > > is tricky to handle because you want grep to produce exit statuses that > xargs will process to produce the exit status you want. > > I think this will get the effect you want: > > ... | xargs bash -c "grep $regex ; [[ \$? -le 1 ]]' > > and it runs grep no more times than "xargs grep" will. The problem with something based on ... | xargs bash -c ... is that it would make it easy to inject commands in the bash script with malicioulsy crafted files, right? It sounds scary. Have a lovely day! Alex > > Dale -- <https://www.alejandro-colomar.es> Use port 80 (that is, <...:80/>).
[signature.asc (application/pgp-signature, inline)]
bug-grep <at> gnu.org:bug#79728; Package grep.
(2025年10月30日 16:56:02 GMT) Full text and rfc822 format available.Message #14 received at 79728 <at> debbugs.gnu.org (full text, mbox):
From: Paul Eggert <eggert <at> cs.ucla.edu> To: Alejandro Colomar <alx <at> kernel.org> Cc: 79728 <at> debbugs.gnu.org Subject: Re: bug#79728: Flag to return 0 if no match Date: 2025年10月30日 10:55:28 -0600
On 10/30/25 09:11, Alejandro Colomar via Bug reports for GNU grep wrote: >> ... | xargs bash -c "grep $regex ; [[ \$? -le 1 ]]' >> >> and it runs grep no more times than "xargs grep" will. > The problem with something based on > > ... | xargs bash -c ... > > is that it would make it easy to inject commands in the bash script with > malicioulsy crafted files, right? If an attacker controls the regex you're already in trouble, because the regex can be arbitrarily slow. That being said, to avoid the regex being interpreted as shell code, you can use something like this: xargs sh -c 'grep -e "0ドル" -- "$@"; [ $? -le 1 ]' "$regex" Admittedly a bit awkward, but it works now and it's portable to any POSIX platform. If this awkwardness is to be simplified it should be a patch to GNU xargs not to grep, as programs like diff and cmp behave like grep and it's not reasonable to add options to them all merely to work around an xargs awkwardness.
bug-grep <at> gnu.org:bug#79728; Package grep.
(2025年10月30日 17:24:02 GMT) Full text and rfc822 format available.Message #17 received at 79728 <at> debbugs.gnu.org (full text, mbox):
From: Collin Funk <collin.funk1 <at> gmail.com> To: Paul Eggert <eggert <at> cs.ucla.edu> Cc: 79728 <at> debbugs.gnu.org, Alejandro Colomar <alx <at> kernel.org> Subject: Re: bug#79728: Flag to return 0 if no match Date: 2025年10月30日 10:23:32 -0700
Paul Eggert <eggert <at> cs.ucla.edu> writes: > On 10/30/25 09:11, Alejandro Colomar via Bug reports for GNU grep wrote: >>> ... | xargs bash -c "grep $regex ; [[ \$? -le 1 ]]' >>> >>> and it runs grep no more times than "xargs grep" will. >> The problem with something based on >> ... | xargs bash -c ... >> is that it would make it easy to inject commands in the bash script >> with >> malicioulsy crafted files, right? > > If an attacker controls the regex you're already in trouble, because > the regex can be arbitrarily slow. Or exhaust your systems memory in the case of: $ grep -E 'a+++++++++++++++++++++++++++++++++++++++' COPYING Among many others. :) Collin
bug-grep <at> gnu.org:bug#79728; Package grep.
(2025年10月30日 17:54:02 GMT) Full text and rfc822 format available.Message #20 received at 79728 <at> debbugs.gnu.org (full text, mbox):
From: Alejandro Colomar <alx <at> kernel.org> To: Paul Eggert <eggert <at> cs.ucla.edu> Cc: 79728 <at> debbugs.gnu.org Subject: Re: bug#79728: Flag to return 0 if no match Date: 2025年10月30日 18:53:19 +0100
[Message part 1 (text/plain, inline)]
Hi Paul, On Thu, Oct 30, 2025 at 10:55:28AM -0600, Paul Eggert wrote: > On 10/30/25 09:11, Alejandro Colomar via Bug reports for GNU grep wrote: > > > ... | xargs bash -c "grep $regex ; [[ \$? -le 1 ]]' > > > > > > and it runs grep no more times than "xargs grep" will. > > The problem with something based on > > > > ... | xargs bash -c ... > > > > is that it would make it easy to inject commands in the bash script with > > malicioulsy crafted files, right? > > If an attacker controls the regex you're already in trouble, because the > regex can be arbitrarily slow. I'm not too worried about DoS. I was worried about remote code execution. As in, I'll try to search for something in an arbitrary directory, possibly controlled by a malicious actor, and file names or contents could result in giving them control of my computer. > That being said, to avoid the regex being interpreted as shell code, you can > use something like this: > > xargs sh -c 'grep -e "0ドル" -- "$@"; [ $? -le 1 ]' "$regex" Hmmm, it seems like what I want. Testing seems to work: alx <at> devuan:~/tmp$ cat script #!/bin/bash set -Eeuo pipefail echo foo bar baz | xargs sh -c 'echo "0ドル" -- "$@"; test $? -le 1;' "regex"; alx <at> devuan:~/tmp$ ./script regex -- foo bar baz > > Admittedly a bit awkward, but it works now and it's portable to any POSIX > platform. This sounds quite robust; thanks! > If this awkwardness is to be simplified it should be a patch to GNU xargs > not to grep, as programs like diff and cmp behave like grep and it's not > reasonable to add options to them all merely to work around an xargs > awkwardness. Makes sense; thanks! But I think I like your approach above; I don't need simplifying it. Have a lovely night! Alex -- <https://www.alejandro-colomar.es> Use port 80 (that is, <...:80/>).
[signature.asc (application/pgp-signature, inline)]
bug-grep <at> gnu.org:bug#79728; Package grep.
(2025年10月31日 00:49:02 GMT) Full text and rfc822 format available.Message #23 received at 79728 <at> debbugs.gnu.org (full text, mbox):
From: Alejandro Colomar <alx <at> kernel.org> To: Paul Eggert <eggert <at> cs.ucla.edu> Cc: 79728 <at> debbugs.gnu.org, chet.ramey <at> case.edu Subject: Re: bug#79728: Flag to return 0 if no match Date: 2025年10月31日 01:48:10 +0100
[Message part 1 (text/plain, inline)]
[CC += Chet] Hi Paul, Chet, On Thu, Oct 30, 2025 at 06:53:22PM +0100, Alejandro Colomar wrote: > > That being said, to avoid the regex being interpreted as shell code, you can > > use something like this: > > > > xargs sh -c 'grep -e "0ドル" -- "$@"; [ $? -le 1 ]' "$regex" I've applied the following commit: commit 243666cfbab9d0bdb26424f1ba9cae8e5571cf68 Author: Alejandro Colomar <alx <at> kernel.org> Date: Fri Oct 31 00:58:42 2025 +0100 src/bin/grepc: Handle xargs(1) errors properly 'xargs grep' is hard, because grep(1) exits with a status of 1 for no match, which is not an error, but xargs(1) takes that as an error. This trick with sh(1) was suggested by Paul, and nicely solves this problem. Link: <https://lists.gnu.org/archive/html/bug-grep/2025-10/msg00029.html> Suggested-by: Paul Eggert <eggert <at> cs.ucla.edu> Signed-off-by: Alejandro Colomar <alx <at> kernel.org> diff --git a/src/bin/grepc b/src/bin/grepc index 9f6de55d7..300a3b6c9 100755 --- a/src/bin/grepc +++ b/src/bin/grepc @@ -238,18 +238,16 @@ opts=($A $B $C $c $h $i $l -M $m $n); if test -z "$*"; then - pcre2grep "${opts[@]}" -f "$patterns" || true; + pcre2grep "${opts[@]}" -f "$patterns" || test $? -eq 1; else find "$@" -type f -print0 \ | if test -z "$c"; then # shellcheck disable=SC2248 # $i may be -i or nothing. - xargs -0 grep -lZPI $i -- "$identifier" || true; + xargs -0 sh -c 'grep -lZPI $i -e "0ドル" -- "$@" || test $? -eq 1;' "$identifier"; else cat; fi \ - | { - xargs -0 pcre2grep "${opts[@]}" -f "$patterns" || true; - }; + | xargs -0 sh -c 'pcre2grep '"${opts[*]}"' -f "0ドル" -- "$@" || test $? -eq 1;' "$patterns"; fi \ | if test "$r" = 'yes'; then perl -p -e 's/('"$identifier"')/033円[32m1円033円[0m/'; I've also had an idea for trying to keep the return value of 1 when there are no matches. I could send a USR1 signal from grep(1). I've written this proof-of-concept: alx <at> devuan:~/tmp/g$ cat script2 #!/bin/bash set -Eeuo pipefail; shopt -s lastpipe; trap 'exit 2;' ERR; trap 'exit 1;' USR1; find "$@" -type f \ | xargs bash -c 'grep -e "0ドル" -- "$@" || { test $? -eq 1 && kill -USR1 '"$$"'; };' 'foo'; However, if find(1) fails, grep(1) still sends this signal, and that seems to have preference over the ERR trap. $ ./script2 nonexistent; echo $? find: ‘nonexistent’: No such file or directory 1 Do you know of any way to achieve that? I'd like to avoid sending other signals from find, as the actual script is much more complex, and sending signals from every command in the pipeline would be tedious (and likely error prone). Have a lovely night! Alex -- <https://www.alejandro-colomar.es> Use port 80 (that is, <...:80/>).
[signature.asc (application/pgp-signature, inline)]
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.