You grep
one file at a time. With your -quit
, you stop the find at the first successful grep.
[update] My first solution was to grep mutiple files at once:
find /path/ -type f -exec grep -H -m 1 'pattern' \{\} + -quit | head -n 5
(the magic is in the +
at the end of the -exec
sub-command. Added -type f
. You may want to remove the -H
option to grep
if you are certain that /path/ contains several files)
The problem here, as reported by @StéphaneChazelas, is that the -exec
command is executed asynchronously and returns always true
=> find
quits at the first file.
If we want find
to stop when head
has finished, find
must also receive the SIGPIPE that grep
is getting (signal 13). That means that find
must send something through the pipe.
Here is a quick-and-dirty hack, enhanced with Stéphane's suggestions:
find /path/ -type f -exec grep -H -m 1 --line-buffered 'pattern' {} + -printf '\r' | head -n 5
With -printf '\r'
I force find
to output a harmless character that will (hopefully) not alter the output of grep
. Once head
has stopped, find
will receive a SIGPIPE and stop too.
[update2] I warned you that this is a dirty hack. Here is a better solution:
find /path/ -type f -exec grep --quiet 'pattern' {} ";" -print | head -n 5
Here, this is no longer grep
that prints the filename, but find
=> no more "grep terminated by signal 13" and find
stops with head
. The problem is that matched lines are no longer printed by grep
.
[update3] Finally, as suggested by @Andrey, the shamelessly hideous command below would solve this last issue:
find /path/ -type f \
-exec grep --quiet 'pattern' {} \; \
-printf '%p:' \
-exec grep -h -m 1 'pattern' {} \; \
| head -n 5`
find
has a built-in option to stop after first match, but no means of counting. – Toby Speight Dec 12 '16 at 12:01