How to find first match in multiple files

6,970

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}' {} \;
Share:
6,970

Related videos on Youtube

gaberlunzie
Author by

gaberlunzie

Updated on September 18, 2022

Comments

  • gaberlunzie
    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 or head -n 1.

  • gaberlunzie
    gaberlunzie almost 11 years
    I'd like to search the first match for each of the files rather than quit after the first file.
  • gaberlunzie
    gaberlunzie almost 11 years
    I'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
    Kevin almost 11 years
    Why are you using -quit? That tells find to exit after the first match.
  • gaberlunzie
    gaberlunzie almost 11 years
    I'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
    suspectus almost 11 years
    This command should do just that. It will continue searching each file regardless of any match of any file that find examines.