Here is my script
eval "find \\( -type f -a \\( -name '*.h' \\) \\) -print0" | xargs -0 -n100 grep -f <(echo "stdio")
echo $?
Nothing is found and the exit code is 123.
If I modify it a little as follows
echo "stdio" >.P
eval "find \\( -type f -a \\( -name '*.h' \\) \\) -print0" | xargs -0 -n100 grep <.P
echo $?
Something is found but the exit code is still 123.
So what is wrong?
======================================================================
Actually I just want to write a small script to make find+xargs+grep easier. For exmaple,
xgrep -e PATTERN1 -e PATTERN2 ... *.c *.h
is to execute
find -name *.c -o -name *.h|xargs grep -f <(echo "$PATTEN1
$PATTERN2")
Use -f option instead of -e is to avoid troubles in escaping single or double quations within the patterns.
#!/bin/bash
#set -e -o pipefail
eval ARGV=($(getopt -l '' -o 'e:li' -- "$@")) || exit 1
for((i=0;i<${#ARGV[@]};i++)) {
o="${ARGV[$i]}"
case $o in
-e)
i=$((i+1));
a="${ARGV[$i]}"
if [ -n "$grep_patterns" ]; then
grep_patterns="$grep_patterns"$'\n'
fi
grep_patterns="$grep_patterns$a"
;;
-i)
grep_options="$grep_options -i"
;;
-l)
grep_options="$grep_options -l"
;;
--)
i=$((i+1));
break;;
esac
}
for((;i<${#ARGV[@]};i++)) {
if [ -n "$find_options" ]; then
find_options="$find_options -o "
fi
find_options="${find_options}-name '${ARGV[$i]}'"
}
cmd="find \\( -type f -a \\( $find_options \\) \\) -print0"
eval "$cmd" | xargs -0 grep $grep_options -f <(echo "$grep_patterns")
123 means "any invocation exited with a non-zero status". So xargs
ran grep
at least twice (because you fed it so many files that they would exceed the maximum command line length, which you limited to 100 files) and at least one of the invocations was on a set of files which contained no matches, which caused the exit code from grep
to be nonzero (failure).
Perhaps you should explain what you are trying to accomplish. The eval
looks superfluous and the double redirection is probably not accomplishing what you want (grep
's standard input cannot simultaneously be connected to the pipe from eval
and to .P
).
If you want to parametrize the first argument to grep
, maybe do something like
#!/bin/sh
find -type f -name '*.h' -print0 |
xargs -0 -n100 grep "$1"
... where you invoke this with e.g. stdio
as the first argument.
(Notice also the much simplified parameters to find
. You only have two predicates so there is no need to parenthesize anything, and then the -a
can be dropped, too.)
The exit code will still be 123 if there are grep
invocations which return zero matches. You can reduce the chances by omitting the -n 100
(which hardly seems to serve any useful pupose anyway) but if you want to absolutely prevent it, you can feed the entire pipeline to | grep .
which will report success if there was any output. (Or you could run xargs
on a wrapper which always returns success if the exit code from grep
is either 0 or 1, but that is more complex, and you will then see "success" even in the case of zero matches.)
I'm posting this as a separate answer in response to your recent edit. I don't particularly want to change my existing answer, which already addresses the fundamental question.
Your script is unfortunately a classic example of the problem described in http://mywiki.wooledge.org/BashFAQ/050: "I am trying to put my command in a variable, but"...
The short version is "don't do that". The long version is, try to use arrays, and avoid variables where they are not absolutely necessary. Here is an attempt at refactoring your tool along those lines.
#!/bin/bash
#set -e -o pipefail
grep_patterns=( )
grep_options=( )
eval ARGV=($(getopt -l '' -o 'e:li' -- "$@")) || exit 1
for((i=0;i<${#ARGV[@]};i++)) {
case ${ARGV[$i]} in
-e) i=$((i+1))
grep_patterns+=("-e" "${ARGV[$i]}") ;;
-i | -l)
grep_options+=("${ARGV[$i]}") ;;
--) i=$((i+1));
break;;
esac
}
find_options=("${ARGV[@]:$i}")
find -type f -a \( "${find_options[@]}" \) -print0 |
xargs -0 grep "${grep_options[@]}" "${grep_patterns[@]}"
I'm not sure passing multiple -e
options to grep
is supported everywhere, but it works fine with GNU grep
and simplifies things to my mind.
来源:https://stackoverflow.com/questions/26540813/got-exit-code-123-in-find-xargs-grep