find -exec grep {} \; egrep -v string \; # the command chain brakes

1

1

I'm playing with find command to see how it behaves and I'm a bit lost.

First bit is fine :

find . -maxdepth 1 -exec grep -l abc {} \;
grep: .: Is a directory
./file2.pdf
./file1

Then I try to exclude the .pdf file by chaining another egrep command but I fail.

find . -maxdepth 1 -exec grep -l abc {} \; -exec egrep -vl '*.pdf' {} \;
grep: .: Is a directory
./file2.pdf
./file2.pdf
./file1
./file1

Why it doesn't exclude the .pdf file and also prints the result two times ?

Tomas.R

Posted 2019-10-26T18:00:58.843

Reputation: 35

Answers

2

egrep -vl '*.pdf' some_file examines the file content, not name.

The right way to exclude names with find is to negate (!) a proper -name (or -iname if available) expression. Example:

find . -maxdepth 1 ! -name '*.pdf' -exec grep -l abc {} \;

Each result was printed twice because after the first grep printed it and returned success, the second one (egrep) apparently didn't find *.pdf (interpreted as an extended regular expression) in the respective file content and thus (mind the -v) printed the same name.

Note -exec is also a test. In your case if the first -exec reports failure then the second -exec will not be triggered. The first -exec will report failure if its grep reports failure. And the grep will report failure if it doesn't find the pattern in the file. This means any file that is not printed by the first grep cannot be printed by the second one (egrep) because the second one doesn't even run for the file.


Another way to exclude .pdf files is to filter the output of your first find (which in your case is in fact the output of greps; your find prints nothing by itself). Like this:

find . -maxdepth 1 -exec grep -l abc {} \; | grep -iv '\.pdf$'

But if any path returned by find is multi-line (i.e. if it includes newlines; filenames in Linux can) then the added grep will perceive each line separately anyway, as if the lines referred to more than one file; and you will get unexpected results. Therefore testing inside find (-name …) is better.

Kamil Maciorowski

Posted 2019-10-26T18:00:58.843

Reputation: 38 429