Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Simple Script Please Help

Status
Not open for further replies.

YouEnjoyMyself

IS-IT--Management
Jul 27, 2004
111
US
Hello,

I am writing a script that parses a log file into an excel spread sheet (.csv). The sample input (posted below) ends up giving me 24 different entries for each field requested to be parsed. Go ahead and run it you will get a better idea of what I mean. I would greatly appreciate any help, This forum has been a great help to me in the past. Thank you in advance! I have attached the script and a sample input below:


#This program will report the tapes created within the last 875 hours
#!/opt/nokianms/bin/perl
#opens bpimagelist.cmd
$DATA= "C:\\vmquery.txt";
open (DATA, "$DATA") or die "Can't open $DATA: $!\n";
#opens Tapelog.txt (Data)
open(CSVFILE, ">C:\\vmquery.csv") || die qq(Can't open "vmquery.csv " for output.\n);
#creates Tapes_To_Be_Pulled.csv (output file)
print CSVFILE "Media ID,Volume Pool,Date Created,Date Assigned,Expiration Date,status\n";
#Below parses Tapelog.txt for the listed fields
while (<DATA>) {
chomp;
s{s*\d+:\d+:\d+\s*\)
}{}x; #Takes C time off of the Media Date listing, or any other time listing in logfile.
$_=~ s/^\s+//; $_ =~ s/\s+$//;
my ($key, $value) = ($_=~ m!(.+): (.+)!);
$value =~ s/^\s+//; $value =~ s/\s+$//;
print "$key,$value\n";
$mediaid = $value if (/^media ID/);
$volumepool = $value if (/^volume pool/);
$created = $value if (/^created:/);
$assigned= $value if (/^assigned:/);
$expirationdate = $value if (/^expiration date:/);
$status = $value if (/^status/);
print CSVFILE "$mediaid,$volumepool,$created,$assigned,$expirationdate,$status\n";
}


close(CSVFILE) || die qq(Can't close input file "Tapelog.txt".\n);
close(DATA) || die qq(Can't close output file "Tapes_To_Be_Pulled.csv".\n);


Sample input:

================================================================================
media ID: 000724
media type: 1/2" cartridge tape (6)
barcode: 000724
media description: ---
volume pool: Samples (59)
robot type: NONE - Not Robotic (0)
volume group: ---
vault name: ---
vault sent date: ---
vault return date: ---
vault slot: ---
vault session id: ---
vault container id: -
created: 10/7/2002 9:47:48 AM
assigned: 12/14/2003 8:10:03 PM
last mounted: 12/14/2003 8:11:03 PM
first mount: 10/8/2002 6:56:18 PM
expiration date: ---
number of mounts: 51
max mounts allowed: ---
status: 0x0
=
 
the first time it does the loop

Code:
while (<DATA>) {
....

it prints

Code:
print CSVFILE  "$mediaid,$volumepool,$created,$assigned,$expirationdate,$status\n";

in the csv file

BUT while it reads the first line it does not find any of the variables that you asign to print

so it doesn't print anything Untill it finds something to asign to them

It does this as many times as many are the lines in the file vmquery.txt.
so try to put all your variables into arrays or a hash

and after

Code:
close(DATA) || die qq(Can't close output file "Tapes_To_Be_Pulled.csv".\n);

open the csv and print inside the results.
 
Catchy moniker...

No help on your problem, sorry. I don't follow what you're doing with $_ and $value in your loop.
 
Code:
my $DATA= "C:\\vmquery.txt";

open (DATA, "$DATA") or die "Can't open $DATA: $!\n";
	open(CSVFILE, ">C:\\vmquery.csv") || die qq(Can't open "vmquery.csv " for output.\n);
		print CSVFILE "Media ID,Volume Pool,Date Created,Date Assigned,Expiration Date,status\n";
		
		while (<DATA>) {
			chomp;   
			s{s*\d+:\d+:\d+\s*\)}{}x;
			$_=~ s/^\s+//; $_ =~ s/\s+$//;      
			my ($key, $value) = ($_=~ m!(.+): (.+)!);
			$value =~ s/^\s+//; $value =~ s/\s+$//;
			print "$key,$value\n";     
			push (@array,$_);			
			$mediaid = $value if (/^media ID/);
			$volumepool = $value if (/^volume pool/);
			$created = $value if (/^created:/);
			$assigned= $value if (/^assigned:/);
			$expirationdate = $value if (/^expiration date:/);
			$status = $value if (/^status/);
		}
		print CSVFILE  "$mediaid,$volumepool,$created,$assigned,$expirationdate,$status\n";

	close(CSVFILE) || die qq(Can't close input file "Tapelog.txt".\n);
close(DATA) || die qq(Can't close output file "Tapes_To_Be_Pulled.csv".\n);

this will do it , and i'm sure you can even make it look beter if you find a method to asign your variables into a hash or array;
 
hash would be best here methinks
Code:
while (<DATA>) {
  if ($_ ne "----------------") {     
     ($key,$value)=split/:/, $_;
     $hash{$key}=$value;
  } else {
     print "$hash{'mediaid'},$hash{'volumepool'},$hash{'created'},$hash{'assigned'},$hash{'expirationdate'},$hash{'status'}\n";
     $hash{mediaid}='';
     #reset the rest of your hash values here
     ...
  }
}

might need to include a trim function to tidy the output a bit though

--Not TESTED

HTH
--Paul

cigless ...
 
I agree with Paul that a hash is called for. Here's my attempt:
Code:
#!perl
use strict;
use warnings;

#keywords to look for 
my @keywds = ('media ID',
              'volume pool',
              'created',
              'assigned',
              'expiration date',
              'status',
);
#construct header from keywds
my $header = join(",", 
    map {
        (my $x = $_) =~ s/\b([a-z])/\U$1/g; #uc first char of words
        $x =~ /^Created|Assigned/? 'Date ' . $x: $x;
    } @keywds
);
#make hash with keywds as keys for quick lookup
my %kw;
@kw{@keywds} = (); 

my %temp;
my @data;

while (<DATA>) {
    chomp;   
    s/\s+$//;
    s{s*\d+:\d+:\d+\s*}{}x; #Takes C time off (see [b]Note[/b])
    my ($key, $value) = split /:\s+/;
    if (exists($kw{$key})) {
        $temp{$key} = $value;
        if ($key eq $keywds[-1]) {
            push(@data, { %temp });
            %temp = ();
        }
    }
}
#write the file
my $outfile = "c:/work/perl/vmquery.csv";
open(CSVFILE, ">$outfile") || die qq(Can't open "$outfile" for output.\n);
print CSVFILE "$header\n";

for my $row (@data) {
    for (my $i=0; $i<@keywds; $i++) {
        print CSVFILE $row->{$keywds[$i]}, $i<@keywds - 1? ",": "\n";
    }
}
close(CSVFILE) || die qq(Can't close output file "$outfile".\n);

__DATA__
================================================================================
media ID:              000724
media type:            1/2" cartridge tape (6)
barcode:               000724
media description:     ---
volume pool:           Samples (59)
robot type:            NONE - Not Robotic (0)
volume group:          ---
vault name:            ---
vault sent date:       ---
vault return date:     ---
vault slot:            ---
vault session id:      ---
vault container id:    -
created:               10/7/2002 9:47:48 AM
assigned:              12/14/2003 8:10:03 PM
last mounted:          12/14/2003 8:11:03 PM
first mount:           10/8/2002 6:56:18 PM
expiration date:       ---
number of mounts:      51
max mounts allowed:    ---
status:                0x0
=
This seems to do what you want. Note that I modified your regex to "Take the C time off" as it did not match the date formats in your data. As posted, it looked for 3 colon-separated groups of digits followed by zero or more whitespace chars followed by a closing paren. Also, the /x modifier serves no purpose here. /x allows arbitrary whitespace in re's for greater readability, including continuing re's on multiple lines. Not needed here. I left it in just in case you have some reason for using it that I don't fathom.

Here what @data looks like in Data::Dumper:
Code:
@data = (
          {
            'media ID' => '000724',
            'volume pool' => 'Samples (59)',
            'created' => '10/7/2002 AM',
            'assigned' => '12/14/2003 PM',
            'expiration date' => '---',
            'status' => '0x0'
          }
        );

Here's what the (one-line) file looks like:
Code:
Media ID,Volume Pool,Date Created,Date Assigned,Expiration Date,Status
000724,Samples (59),10/7/2002 AM,12/14/2003 PM,---,0x0
HTH



 
Mike,

Might sound like a dumb question, but what if my DATA is coming from a flat text file? I tried making some changes to the script to accomodate this but I couldnt get it to work. Thanks.

 
Just open your input file before the while loop, e.g.
Code:
my $infile = "C:\\vmquery.txt";
open (INFILE, "<$infile") || die qq(Can't open "$infile"!\n);
while (<INFILE>) {
...
and close it after the end of the while
Code:
close(INFILE) || die qq(Can't close input file "$infile"!\n);

 
Just open your input file before the while loop, e.g.
Code:
my $infile = "C:\\vmquery.txt";
open (INFILE, "<$infile") || die qq(Can't open "$infile"!\n);
while (<INFILE>) {
...
and close it after the end of the while
Code:
close(INFILE) || die qq(Can't close input file "$infile"!\n);


 
Mike,

If you are ever in the upstate New York area I owe you a neckbone and a Beer. Thanks.


 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top