5

How might one search the first 50 lines of files in a directory for a given string? I'm specifically looking for which database table files (from mysqldump) define a specific field, but I don't want to grep the whole files, which after 20-40 lines of CREATE TABLE continue on to hundreds of INSERT statements.

I could write a Python script to iterate over the first few lines of each file, but from experience Python, though powerful, is slow. I have over 200 *.sql files to go through, and I'd like to learn a solution which I could generalize in the future anyway.

  • 9
    Python would be done by now. – Aaron Hall Apr 22 '15 at 13:10
  • grep is originally made to find everything matching a given pattern. You're effectively looking for inverse grep. It would be a nice addition to the available toolkit. – Mast Apr 22 '15 at 14:56
10

awk (assuming your implementation supports the nextfile statement) can do this quite nicely:

awk 'FNR > 50 { nextfile }; /foobar/ { print FILENAME ": " $0 }' ./*.sql

The first statement skips to the next file once 50 records have been processed. The second statement prints the filename and the matching line for any line containing foobar.

If your awk doesn't have nextfile this variant works too, although I imagine it will be less efficient:

awk 'FNR <= 50 && /foobar/ { print FILENAME ": " $0 }' ./*.sql
  • Why are you doing ./*.sql instead of just *.sql ? – user78605 Apr 22 '15 at 13:15
  • Stéphane Chazelas added that, to avoid problems with filenames containing =. (See the edit history for this question). – Stephen Kitt Apr 22 '15 at 13:21
  • Why what difference does it make to filenames with = in ? – user78605 Apr 22 '15 at 13:24
  • 2
    @JID, Try for instance after touch ORS=foo.sql – Stéphane Chazelas Apr 22 '15 at 13:24
  • @StéphaneChazelas Ahh right, thanks for the example. I don't need to try it, I can see how that would be a problem. I never notice things like this because i don't use ridiculous filenames. – user78605 Apr 22 '15 at 13:28
6

This solution works, but I feel that it is clumsy. Searching the first 50 lines for the string "foobar":

$ for I in *.sql ; do echo $I && head -n 50 $I | grep foobar ; done
  • Do you search in first 50 lines of each file OR first 50 pattern occurance in each file? – Costas Apr 22 '15 at 12:15
  • You could make this slightly less clumsy with for I in *.sql ; do echo $I && grep foobar <(head -50 "$I"); done or, to only print the file name if it matched: for I in *.sql ; do grep foobar <(head -50 "$I") && echo "$I"; done (but that will print the file name after the matches. – terdon Apr 22 '15 at 12:35
  • @Terdon this will print the filename before the matches: for I in *.sql; do M=$(head -50 "$I" | grep foobar) && echo "$I ==>" && echo "$M"; done – roaima Apr 22 '15 at 13:10
  • 1
    @StéphaneChazelas What's wrong with echo? – Artur Gaspar Apr 22 '15 at 17:05
  • 2
    @ArturGaspar - if you hit votes on top of the page, you'll find the answer in one of the top ten questions. – don_crissti Apr 22 '15 at 20:52
3

In loop way GNU sed can do task too :

for f in *.sql
do
    sed -e '1 F' -e '51 Q' -e '/pattern/! d' "$f"
done
  • 3
    This doesn't print the file name. Have fun searching the match! ;) – FloHimself Apr 22 '15 at 12:21
  • @don_crissti, yes, sed -ns '1,50{/pattern/p}' would work though (but read the files fully so less efficient than awk+nextfile). – Stéphane Chazelas Apr 22 '15 at 16:39
  • 1
    @don_crissti I wonder, which flag is it? – FloHimself Apr 22 '15 at 16:51
  • @FloHimself, he may be referring to the (also GNU-specific) F command. – Stéphane Chazelas Apr 22 '15 at 17:00
  • Note that that code also fails because if the 50th line doesn't match the pattern, 50q is never reached. – Stéphane Chazelas Apr 22 '15 at 17:01
2

Head piped to grep gets you halfway there.

head -50 filename | grep string
  • This won't print the filenames either. Maybe head -50 file* | grep 'pattern\|==> .* <==' assuming no other line in those files matches ==> .* <== – don_crissti Apr 22 '15 at 16:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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