Printing filename along with grep results in find -exec

command linefilenamesfindgrep

I have a program called foo which I want to exec on each result that is found via find. So something like this:

find . -name '*.o' -type f -exec foo {} \;

I want to grep the output of all of these invocations of foo for a certain string bar. So I add this:

find . -name '*.o' -type f -exec foo {} \; | grep bar

But I lose the original information about what files the matches are coming from. I tried adding -fprintf /dev/stderr '%p\n' to the find command but now it looks like stdout is gone, because no grep results are printed.

How can I get each filename printed to the output and THEN have the grep results corresponding to that file printed after?

Alternatively, if there were some way to make the -H argument of grep work that would be fine too, but as written it won't work because I'm just passing text from stdin, and grep doesn't know the filename. I tried various incantations of xargs, but I couldn't get any of that to work either.

Best Answer

To get each filename printed to the output and THEN have the grep results corresponding to that file printed after, you could wrap the -exec foo {} | grep pipe in a shell:

find . -name '*.o' -type f -print -exec sh -c 'foo "$1" | grep "bar"' sh {} \;

To to make the -H argument of grep work with standard input, if your version of grep supports the --label= option you could do

find . -name '*.o' -type f -exec sh -c '
  foo "$1" | grep -H --label="$1" "bar"
' sh {} \;

or (if your find supports the + multi-argument alternative to \;):

find . -name '*.o' -type f -exec sh -c '
  for f; do foo "$f" | grep -H --label="$f" "bar"; done
' sh {} +
Related Question