How to find first match in multiple files
Solution 1
Just use the -m
option of GNU grep
which stops reading the file after (in the example) one match.
find dir -iname '*.ext' -exec grep -m 1 'pattern' {} \;
Solution 2
If the searching command has no way to stop after the first match, you can filter its results and keep only the first output line: command 'pattern' /path/to/file | head -n 1
. The command will receive a SIGPIPE signal when head
exits, so it might go on looking for a few more matches due to buffering but it will stop before the end of the file if there are a lot of matches.
Since you need to run a shell command (to set up the pipe), you need to invoke sh
from find
. Mind the quoting: you need one layer of quotes for the outer shell, and another for the shell started by find
. You can put single quotes around the inner shell command and work in single quotes with the '\''
hack (end single quote literal, \'
for a literal single quote, and start a new single quote literal in the same breath), this way you don't need any different quoting in the pattern (unless the pattern contains a '
that you represented as '\''
, in which case you'll need to make that '\'\\\'\''
).
find dir -iname '*.ext' -exec sh -c 'command '\''pattern'\'' "$0" | head -n 1' {} \;
Instead of worrying about quoting the pattern, you can put it outside and pass it as a parameter.
find dir -iname '*.ext' -exec sh -c 'command "$0" "$1" | head -n 1' 'pattern' {} \;
It will be slightly faster to invoke only one shell and loop over the files.
find dir -iname '*.ext' -exec sh -c '
for f; do command "$0" "$f" | head -n 1; done
' 'pattern' {} +
Solution 3
You could do it with an awk script:
find dir -iname '*.ext' -exec awk '/pattern/{print;exit}' {} \;
Related videos on Youtube
gaberlunzie
Updated on September 18, 2022Comments
-
gaberlunzie over 1 year
Is there a way for the find command to search for the first match or occurrence of a string or pattern within each of multiple files? I've been using the usual syntax:
find dir -iname '*.ext' -exec command 'pattern' {} \;
(I also happen to be searching pdfs with
-exec pdfgrep
but suppose that would be a special case of the general problem and may be dealt with afterwards or separately.)Keep in mind this is not same as the commonly-asked problem of producing the first result from a search using find with
-quit
orhead -n 1
. -
gaberlunzie almost 11 yearsI'd like to search the first match for each of the files rather than quit after the first file.
-
gaberlunzie almost 11 yearsI've tried -quit with -exec (pdf)grep but that only exits after the first result; I'd like to search multiple files for first matches.
-
Kevin almost 11 yearsWhy are you using
-quit
? That tellsfind
to exit after the first match. -
gaberlunzie almost 11 yearsI'm still getting the hang of grep and sed, much less for awk (which I hadn't considered.) Your solution does indeed work (now just to append the filenames that contain the matches, sort of pdfgrep style.)
-
suspectus almost 11 yearsThis command should do just that. It will continue searching each file regardless of any match of any file that find examines.