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.

2
  • 9
    Python would be done by now.
    – Aaron Hall
    Apr 22, 2015 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, 2015 at 14:56

4 Answers 4

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
7
  • Why are you doing ./*.sql instead of just *.sql ?
    – user78605
    Apr 22, 2015 at 13:15
  • Stéphane Chazelas added that, to avoid problems with filenames containing =. (See the edit history for this question). Apr 22, 2015 at 13:21
  • Why what difference does it make to filenames with = in ?
    – user78605
    Apr 22, 2015 at 13:24
  • 2
    @JID, Try for instance after touch ORS=foo.sql Apr 22, 2015 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, 2015 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
6
  • Do you search in first 50 lines of each file OR first 50 pattern occurance in each file?
    – Costas
    Apr 22, 2015 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, 2015 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 Apr 22, 2015 at 13:10
  • 1
    @StéphaneChazelas What's wrong with echo? Apr 22, 2015 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. Apr 22, 2015 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
8
  • 3
    This doesn't print the file name. Have fun searching the match! ;)
    – FloHimself
    Apr 22, 2015 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). Apr 22, 2015 at 16:39
  • 1
    @don_crissti I wonder, which flag is it?
    – FloHimself
    Apr 22, 2015 at 16:51
  • @FloHimself, he may be referring to the (also GNU-specific) F command. Apr 22, 2015 at 17:00
  • Note that that code also fails because if the 50th line doesn't match the pattern, 50q is never reached. Apr 22, 2015 at 17:01
2

Head piped to grep gets you halfway there.

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .