Rosand Liu
Rosand Liu

Reputation: 409

find + grep as an if condition doesn't work as expected

I use find to get all txt files , then use grep to find if a special word in the txt files which find by find command.

if find "/home/test/" -name "*.csv" -exec grep "pattern" {} \;; then
    echo "find it in txt files";
else
    echo "not find in txt files";
fi

The program always outputs "find it" although the conditions are not met.

Upvotes: 1

Views: 420

Answers (2)

oguz ismail
oguz ismail

Reputation: 50805

Unless punctuated by a plus sign, an -exec predicate doesn't affect find's exit status. See:

$ find . -prune -exec test -f {} ';'
$ echo $?
0
$ find . -prune -exec test -f {} '+'
$ echo $?
1

But even with the plus sign, find's exit status is unreliable. It may invoke grep multiple times due to memory limitations, and if any invocation exits with a non-zero value, find's exit status will also be non-zero. In other words, if all invocations of grep find a match but one doesn't, find's exit status will not be zero. This applies to xargs as well.

Here is a way to walk around these constraints:

! find . -name '*.txt' -exec sh -c '! "$@"' _ grep 'pattern' /dev/null {} +

Upvotes: 2

iBug
iBug

Reputation: 37317

find exits normally if all files found are processed. Specifically, this ignores the return code of the command executed.

If you want the exit code of grep, you're better off with xargs, which can send the output of find as command-line arguments to grep. For example:

find ./ -name '*.txt' -print0 | xargs -0r grep "pattern"

This has the advantage that you can still customize find parameters over grep -r.

Of course you can use GNU grep with --exclude and --include for similar features, but find is more powerful for its expressions.

Upvotes: 2

Related Questions