For Programmers: Free Programming Magazines  


Home > Archive > PERL Beginners > October 2006 > IO::Scalar Help









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author IO::Scalar Help
Michael Alipio

2006-10-03, 4:00 am



My Log file looks like this:
Each session contains at most four lines and then it
is separated by newline. I need to grab each session
and put each key/value pair in hash.


Start=2006-10-03.09:09:51
IP=192.168.0.14
User=alex
End=2006-10-03.09:14:10

Start=2006-10-03.09:52:12
IP=192.168.0.15
End=2006-10-03.09:53:56

Start=2006-10-03.09:55:21
IP=192.168.0.16
User=mike

Start=2006-10-03.09:55:38
IP=192.168.0.17
End=2006-10-03.09:56:20


I'm just following an example given to me.. however at
some point, I failed to make it work.



my $logfile = shift @ARGV;
open LOGFILE, $logfile or die $!;
while (<LOGFILE> ){
chomp;
push @data, $_;

}
$logdata = "@data";

local $/ = "";
my $fh = new IO::Scalar \$logdata;
while (my $record = <$fh> ) {
my %extr;
for (qw(Start IP User End)){
$extr{$_} = '';
$extr{$_} = $1 if $record =~ /$_=(.*)/;
}
print "Start:$extr{Start} IP:$extr{IP}
User:$extr{User} End:$extr{End}";
}


The output is ugly :-(.. I tried trimming my logs to
only two sessions:

Start=2006-10-03.02:51:48
IP=192.168.0.14
User=edison
End=2006-10-03.04:17:36

Start=2006-10-03.02:51:49
IP=192.168.0.15
User=arnel
End=2006-10-03.04:17:37


And I got:

Use of uninitialized value in concatenation (.) or
string at formatlogs.pl line 51.
Use of uninitialized value in concatenation (.) or
string at formatlogs.pl line 51.
Use of uninitialized value in concatenation (.) or
string at formatlogs.pl line 51.
Start:2006-10-03.02:51:48 IP=192.168.0.14 User=edison
End=2006-10-03.04:17:36 Start=2006-10-03.02:51:49
IP=192.168.1.15 User=arnel End=2006-10-03.04:17:37 IP:
User: End:

It's even more uglier.. plus, no matter how I insert
the newline... the entire output is still shown as a
single continues line...

Any idea what I am doing?

Thanks.









________________________________________
__________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
John W. Krahn

2006-10-03, 4:00 am

Michael Alipio wrote:
>
> My Log file looks like this:
> Each session contains at most four lines and then it
> is separated by newline. I need to grab each session
> and put each key/value pair in hash.
>
>
> Start=2006-10-03.09:09:51
> IP=192.168.0.14
> User=alex
> End=2006-10-03.09:14:10
>
> Start=2006-10-03.09:52:12
> IP=192.168.0.15
> End=2006-10-03.09:53:56
>
> Start=2006-10-03.09:55:21
> IP=192.168.0.16
> User=mike
>
> Start=2006-10-03.09:55:38
> IP=192.168.0.17
> End=2006-10-03.09:56:20
>
>
> I'm just following an example given to me.. however at
> some point, I failed to make it work.
>
>
>
> my $logfile = shift @ARGV;
> open LOGFILE, $logfile or die $!;
> while (<LOGFILE> ){
> chomp;
> push @data, $_;


You should be using paragraph mode and extracting your data here in the while
loop.


> }
> $logdata = "@data";
>
> local $/ = "";


Paragraph mode works by separating each paragraph based on multiple newlines
however you have removed all newlines from the data so there is just one large
paragraph left.


> my $fh = new IO::Scalar \$logdata;
> while (my $record = <$fh> ) {
> my %extr;
> for (qw(Start IP User End)){
> $extr{$_} = '';
> $extr{$_} = $1 if $record =~ /$_=(.*)/;
> }
> print "Start:$extr{Start} IP:$extr{IP}
> User:$extr{User} End:$extr{End}";
> }


It looks like you want something like:

use warnings;
use strict;

my $logfile = shift;
open LOGFILE, '<', $logfile or die "Cannot open '$logfile' $!";
$/ = '';
while ( <LOGFILE> ) {
my %extr = (
Start => '',
IP => '',
User => '',
End => '',
/^(Start|IP|User|End)=(.+)/mg
);
print "Start:$extr{Start} IP:$extr{IP} User:$extr{User} End:$extr{End}";
}

__END__


However, if you really want to slurp your entire file into a string and
process it like that then something like this may work:

use warnings;
use strict;
use IO::Scalar;

my $logfile = shift;
open LOGFILE, '<', $logfile or die "Cannot open '$logfile' $!";

my $logdata = do { local $/; <LOGFILE> };

my $fh = new IO::Scalar \$logdata;

$/ = '';
while ( <$fh> ) {
my %extr = (
Start => '',
IP => '',
User => '',
End => '',
/^(Start|IP|User|End)=(.+)/mg
);
print "Start:$extr{Start} IP:$extr{IP} User:$extr{User} End:$extr{End}";
}

__END__



John
--
Perl isn't a toolbox, but a small machine shop where you can special-order
certain sorts of tools at low cost and in short order. -- Larry Wall
Rob Dixon

2006-10-03, 8:02 am

Michael Alipio wrote:
>
> My Log file looks like this:
> Each session contains at most four lines and then it
> is separated by newline. I need to grab each session
> and put each key/value pair in hash.
>
>
> Start=2006-10-03.09:09:51
> IP=192.168.0.14
> User=alex
> End=2006-10-03.09:14:10
>
> Start=2006-10-03.09:52:12
> IP=192.168.0.15
> End=2006-10-03.09:53:56
>
> Start=2006-10-03.09:55:21
> IP=192.168.0.16
> User=mike
>
> Start=2006-10-03.09:55:38
> IP=192.168.0.17
> End=2006-10-03.09:56:20
>
>
> I'm just following an example given to me.. however at
> some point, I failed to make it work.
>
>
> my $logfile = shift @ARGV;
> open LOGFILE, $logfile or die $!;
> while (<LOGFILE> ){
> chomp;
> push @data, $_;
>
> }
> $logdata = "@data";
>
> local $/ = "";
> my $fh = new IO::Scalar \$logdata;
> while (my $record = <$fh> ) {
> my %extr;
> for (qw(Start IP User End)){
> $extr{$_} = '';
> $extr{$_} = $1 if $record =~ /$_=(.*)/;
> }
> print "Start:$extr{Start} IP:$extr{IP}
> User:$extr{User} End:$extr{End}";
> }
>
>
> The output is ugly :-(.. I tried trimming my logs to
> only two sessions:
>
> Start=2006-10-03.02:51:48
> IP=192.168.0.14
> User=edison
> End=2006-10-03.04:17:36
>
> Start=2006-10-03.02:51:49
> IP=192.168.0.15
> User=arnel
> End=2006-10-03.04:17:37
>
>
> And I got:
>
> Use of uninitialized value in concatenation (.) or
> string at formatlogs.pl line 51.
> Use of uninitialized value in concatenation (.) or
> string at formatlogs.pl line 51.
> Use of uninitialized value in concatenation (.) or
> string at formatlogs.pl line 51.
> Start:2006-10-03.02:51:48 IP=192.168.0.14 User=edison
> End=2006-10-03.04:17:36 Start=2006-10-03.02:51:49
> IP=192.168.1.15 User=arnel End=2006-10-03.04:17:37 IP:
> User: End:
>
> It's even more uglier.. plus, no matter how I insert
> the newline... the entire output is still shown as a
> single continues line...
>
> Any idea what I am doing?


Hi Michael

You're making life very hard for yourself! First of all there's no neeed to pull
the filename out of @ARGV and do the open and so on yourself: just leave the
@ARGV intact and read using <> and everything else will be done for you.
Secondly it's pointless to read all of the data into a scalar and then read it
again out of there: you may as well process the records as they come in from the
file.

As John points out, the main reason your code is failing is that you've stripped
all the newlines from the data using chomp(), so $logdata continas just a single
line. There will be one space between the fields and two spaces between the
records, so it's still possible to make sense of things from there, but it's a
lot easier if you don't go there in the first place! The program below does all
you want. The output's still a little unpleasant as it uses your original print
format, but you can fix that to do what you need.

HTH,

Rob


use strict;
use warnings;

my %init = map { $_ => '' } qw/Start IP User End/;

local $/ = '';
while (<> ) {
my %extr = %init;
while (/(\S+)=(\S+)/g) {
$extr{$1} = $2;
}
print "Start:$extr{Start} IP:$extr{IP} User:$extr{User} End:$extr{End}\n";
}

**OUTPUT**

Start:2006-10-03.09:09:51 IP:192.168.0.14 User:alex End:2006-10-03.09:14:10
Start:2006-10-03.09:52:12 IP:192.168.0.15 User: End:2006-10-03.09:53:56
Start:2006-10-03.09:55:21 IP:192.168.0.16 User:mike End:
Start:2006-10-03.09:55:38 IP:192.168.0.17 User: End:2006-10-03.09:56:20

Paul Lalli

2006-10-03, 8:02 am

Rob Dixon wrote:

> print "Start:$extr{Start} IP:$extr{IP} User:$extr{User} End:$extr{End}\n";


Seeing that kind of repetition always grates on me. Kind of a visual
version of fingernails on a chalkboard. :-)

print join(' ', map "$_:$extr{$_}" qw/Start IP User End/), "\n";

Now, I'm not saying that *looks* any better, and certainly not that
it's more understandable. But it does get rid of the repetition... :-)

Paul Lalli

nobull67@gmail.com

2006-10-04, 9:57 pm

Rob Dixon wrote:

> my %extr = %init;
> while (/(\S+)=(\S+)/g) {
> $extr{$1} = $2;
> }


I prefer to write that as:

my %extr = (%init, /(\S+)=(\S+)/g );

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com