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

Monks,

I'm trying to parse a syslog for usernames, but I'm having problems with my code. Here is what the log info looks like that I'm parsing:
Sep 12 17:30:02 nt-ca-na CA(Domain-CA): Certificate name 'jsmith.2048' + added to database. Sep 12 20:09:37 nt-ca-na CA(Domain-CA): Certificate name 'ksmith.2048' + added to database. Sep 12 21:25:30 nt-ca-na CA(Domain-CA): Certificate name 'ssmith.2048' + added to database.
I want to match just on the usernames (jsmith.2048) that were added. The code below works, but it enters all the usernames into the @certs array. When I do a print "@certs[0]" I get the following results:
'jsmith.2048''ksmith.2048''ssmith.2048'
What should I do to place each array into it's own entry?

Thanks,
Dru
#!/usr/bin/perl -w use strict; my $calog = "/var/log/ca/ca.log"; my $line; my @certs; open LOG, "$calog" or die "Can't open $calog: $!\n"; while ($line = <LOG>){ if ($line =~ m/added/) { @certs = $line =~ m!\'[-.\w]+\'!g; print @certs; } #end if } #end while

Replies are listed 'Best First'.
Re: Array Problem
by blakem (Monsignor) on Sep 14, 2001 at 02:08 UTC
    How about something like:
    #!/usr/bin/perl -wT use strict; my $calog = "/var/log/ca/ca.log"; my $line; my @certs; # open LOG, "$calog" or die "Can't open $calog: $!\n"; while ($line = <DATA>){ # Switched to __DATA__ j +ust for example if ($line =~ m/\'([-.\w]+)\'\s+added/) { # Make this Regex a bit s +marter push(@certs,$1); # add the piece in parens + above to the @certs array } #end if } #end while print "$_\n" for @certs; # print out the array __DATA__ Sep 12 17:30:02 nt-ca-na CA(Domain-CA): Certificate name 'jsmith.2048' + added to\ database. Sep 12 20:09:37 nt-ca-na CA(Domain-CA): Certificate name 'ksmith.2048' + added to\ database. Sep 12 21:25:30 nt-ca-na CA(Domain-CA): Certificate name 'ssmith.2048' + added to\ database. =output jsmith.2048 ksmith.2048 ssmith.2048

    -Blake

Re: Array Problem
by dga (Hermit) on Sep 14, 2001 at 02:25 UTC

    My example solution:

    #!/usr/bin/perl use strict; my @certs; while(<DATA>) { push @certs, /\'([-.\w]+)\'/ if(/added/); } print join("\n", @certs), "\n"; __DATA__ Sep 12 17:30:02 nt-ca-na CA(Domain-CA): Certificate name 'jsmith.2048' + added to database. Sep 12 20:09:37 nt-ca-na CA(Domain-CA): Certificate name 'ksmith.2048' + added to database. Sep 12 21:25:30 nt-ca-na CA(Domain-CA): Certificate name 'ssmith.2048' + added to database.

    Uses the default $_ instead of the problematic $var=<HANDLE> in a while ( which has a few though rare gotcha cases ). This avoids all the line =~ stuff which confuses what is going on.

    uses push to add elements to the end of the array and the () matching in my RE to get exactly the text I wanted into the array ( the name without quotes ). Popping the quotes into the ()'s will add them to the text that is saved off if that is desired..

    Used DATA handle so the example text could be in a functional example program. You would want to use your real filehandle on an open real file of course.

    Used a statement modifier ( the if(/added/) ) since we want people to see that we are appending to an array inside a while loop, making the rule to append secondary to what is happening.

    At the end @certs has the names added one per element in the array. There is a print to show that that is the case.

Re: Array Problem
by cricket (Acolyte) on Sep 14, 2001 at 04:34 UTC
    i think your regex is fine (though it could be combined into one as blake suggests). when i run the code above, it overwrites the array on each iteration, so it will always contain a single element -- the last in your file. i'd use push:
    open (LOG, "$calog") or die "Can't open $calog: $!\n"; while ($line = <LOG>){ if ($line =~ /\'([\w.]+)\' added/) { push(@certs, $1); } }
    --cricket
Re: Array Problem
by jryan (Vicar) on Sep 14, 2001 at 04:44 UTC

    Well, if the log entries are consistant, why not just a simple split?

    #!/usr/bin/perl -w use strict; my $calog = "/var/log/ca/ca.log"; my $line; my @certs = (); open LOG, "$calog" or die "Can't open $calog: $!\n"; while ($line = <LOG>) { my @entry = split ' ', $line; $certs[@certs] = $entry[7]; } print @certs;

    Update: Quick Fix thanks to blakem.

      $certs[$#certs] = $entry[7];

      Should be one of the following:

      $certs[@certs] = $entry[7]; # OR push(@certs,$entry[7]);
      As you wrote it, $entry[7] would simply overwrite the last element in the array instead of tacking itself onto the end.

      -Blake

Re: Array Problem
by hopes (Friar) on Sep 14, 2001 at 09:59 UTC
    OK, how about this
    #!/usr/bin/perl use strict; my (@certs,@lines); @lines=<DATA>; @certs = grep{/'([-.\w]+)'\s+added/,$_=$1}@lines; #just to check map{print"[$_]\n"}@certs; __DATA__ Sep 12 17:30:02 nt-ca-na CA(Domain-CA): Certificate name 'jsmith.2048' + added to database. Sep 12 20:09:37 nt-ca-na CA(Domain-CA): Certificate name 'ksmith.2048' + not added to database. Sep 12 21:25:30 nt-ca-na CA(Domain-CA): Certificate name 'ssmith.2048' + added to database.
    Hopes