[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 <[email protected]>
        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 <[email protected]>
            Signed-off-by: Alejandro Colomar <[email protected]>

        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[32m\1\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@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/>).

Attachment: signature.asc
Description: PGP signature

Reply via email to