Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I need to search the first 50 lines of every file in a directory and its subdirectories.

This will do the recursive part, but how do I limit to just the first 50 lines of each file?

grep -r "matching string here" .

Some of these files are huge, and I only want them to match in the first 50 lines. I'm trying to speed up the process by not searching megabytes of binary data in some files.

share|improve this question
    
do you want to just know the files that match, or do you want to have just the matching string or do you want the matching string together with the filename? –  gniourf_gniourf Oct 29 '13 at 19:13

3 Answers 3

up vote 4 down vote accepted
  • If you just want the files that match:

    find . -type f -exec bash -c 'grep -q "matching string here" < <(head -n 50 "$1")' _ {} \; -printf '%p\n'
    

    or

    find . -type f -exec bash -c 'grep -q "matching string here" < <(head -n 50 "$1") && printf '%s\n' "$1"' _ {} \;
    
  • If you only want the matching strings:

    find . -type f -exec head -n 50 {} \; | grep "matching string here"
    

    or, better,

    find . -type f -exec head -q -n 50 {} + | grep "matching string here"
    
  • And if you want both:

    find . -type f -exec bash -c 'mapfile -t a < <(head -n 50 "$1" | grep "matching string here"); printf "$1: %s\n" "${a[@]}"' _ {} \;
    

Remarks.

  • Could be slightly easier with sed instead of the combo head--grep.
  • Let me stress that all three methods are 100% safe regarding file names that may contain funny symbols (spaces, newlines, etc.).
  • In two of these methods, I'm assuming you have a decently recent version of bash.
  • You could use -exec ... + in each method, but then you'll have to code your inner loop yourself! (trivial exercise left to the reader). This might be very slightly more efficient if you have a gazillion files.
share|improve this answer

If you need the grep output as in the original, you could do:

find . -type f | while read f; do 
  if head -n 50 "$f"|grep -s "matching string here"; then
    grep "matching string here" "$f" /dev/null 
  fi
done

If you only need the file names you can replace the 2nd grep with echo "$f".

share|improve this answer

You'll need to combine a few different utilities to get the desired functionality. Use the find command to recurse the directories, find all files and execute the head command on each file found. The head command can be used to dump only the first 50 lines of each file. Finally, pipe the output to grep to search for your desired string.

find . -type f -exec head -n 50 {} ";" | grep "matching string here"

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.