pmonk4ever has asked for the wisdom of the Perl Monks concerning the following question:

I need to search the source file directories for all *.c & *.h which are using any of 4 constants which are defined in a @Constants list.

Then spit out the path, filename, and the source lines where used, as they are found, to the screen. I can use tee to display to CRT & log into a file if needed later.

The OS is SGI Unix, PERL 5.6.1

I have pulled together a couple of subs, one which will search a single file for the constants, the other to print the source line to the CRT.

I have looked thru the Q & A & the CPAN examples, but was unable to find anything like this. I will be happy to post the final solution for others learn from as well.

I thought this could all be written in Perl, but I just can't seem to get this script started. Can anyone help with an example of what I want?

Thanks in advance.

ki6jux

The examples for Find::File are a bit sparse, are there any other code snippets around?

I got the shell answer to work, but I'd still like to solution this in Perl, for the experience, as a test developer, I don't get to code as much as I'd like to!

ki6

UPDATE

Thank you my fellow Monks for your quick responses! I have reached a dual solution, one in 'C' Shell, and a very elegant one in Perl, which I shall post for fellow Monks to observe and learn ...

You have renewed my faith in my fellow man/woman! Thank you!

ki6jux

  • Comment on Search thru directories of .c & .h files for @Constants

Replies are listed 'Best First'.
Re: Search thru directories of .c & .h files for @Constants
by GrandFather (Saint) on Sep 19, 2007 at 00:02 UTC

    The bits you need to get started are File::Find to scan for the files and something like the following code to build a regex used in the search:

    use strict; use warnings; my @constants = qw(foo bar baz); my $match = '\b' . join ('\b|\b', @constants) . '\b'; while (<DATA>) { print if /$match/; } __DATA__ A foo line no hit bar line barren line No food here foo_bar_baz doesn't hit too

    Prints:

    A foo line bar line

    DWIM is Perl's answer to Gödel
Re: Search thru directories of .c & .h files for @Constants
by dave_the_m (Monsignor) on Sep 18, 2007 at 23:17 UTC
    Not a Perl solution, but if you just want a quick result:
    $ find . -name '*.[ch]' | xargs egrep -w 'foo|bar|baz|boz'

    Dave.

      Ok, removed the h, and now it works...hmmm...well I can write a 2 line script, one for the *.c's and one for the *.h's !!!

      So it worked, with a tweak or 2...i like it because it's simple...but I still want to 'Perlize' it...

      Just for the experience!

      Thanks for your advice and help!

      ki6jux

      The -w option was unknown, so I removed that.

      Then it ran without finding the file, test_code.c in the current directory. So I looked up the commands, to better understand what we were doing...it should work, but it just returns empty...no printout at all.

      ki6jux

      my rep now stands @ -3...

        egrep --recursive --include=*.[ch] 'foo|bar|baz|boz' *

        But you need an advanced grep, such as gnu grep.

        A word spoken in Mind will reach its own level, in the objective world, by its own weight
Re: Search thru directories of .c & .h files for @Constants
by derby (Abbot) on Sep 19, 2007 at 12:26 UTC

    All the find, grep, egrep and File::Find answers are relevant but I'm really starting to like ack (or App::Ack) for this type of thing.

    ack --type=cc 'foo|bar|baz'

    -derby
Re: Search thru directories of .c & .h files for @Constants
by scorpio17 (Canon) on Sep 19, 2007 at 14:29 UTC
    I've done somthing similar before myself. I think you want something like this:
    use strict; use File::Find; # Perl script to search files for particular strings. # Recurses into subdirectories. # If you don't specify a directory to search on the command line, # it will default to the current directory. # define strings to look for here: my @Constants = ( "foo", "bar", "baz", ); my $path = $ARGV[0] || "."; my $count=0; find( sub { my $n = $File::Find::name; # search for files ending in .h or .c if ($n =~ /\.h$/ || $n =~ /\.c$/ ) { ++$count; # might want to use die instead of warn open(IN, "$n") or warn "can't open file $n : $! "; while (<IN>) { my $line = $_; for my $search_string (@Constants) { # the "i" makes the match case insensitive if ($line =~ /$search_string/i) { # print filename and line number and matching string print "$n : $. : $search_string\n"; } } } close (IN); } }, $path); print "Found matches in $count files.\n";

    update: Fixed typo in original post - the path should default to the current working directory. Also, looking at Grandfather's reply, if you want a pattern like "foo" to NOT match something like "food" or "foobar", change the pattern match line to this:

    if ($line =~ /\b$search_string\b/i) {

    This adds "end of word boundary" around the pattern.

      Yes!

      I understand this code and I need case sensitivity, so I can remove the i switch.

      This looks very cool, and I will type it in right away...!!! I was here late last night looking at the Find::File CPAN entries...but they just didn't make any sense to me...maybe it was too late... :D

      Thanks scorpio17!

      I will spend some time playing with this script!

      Thanks to all the Monks for your feedback, it was very instructive. I will post the final version out on the Code Catacombs for others to share!

      Cheers! 8)

      ki6jux