PERL question

Hello,

pkzipc of a certain zip file yeilds the following in shell

PKZIP(R)  Version 6.0  FAST!  Compression Utility for AIX
Copyright 1989-2002 PKWARE Inc.  All Rights Reserved. Registered Version
PKZIP Reg. U.S. Pat. and Tm. Off.  Patent No. 5,051,745

Viewing .ZIP: test.zip

  Length Method     Size  Ratio    Date     Time   CRC-32  Mode   Name
  ------ ------     ----  -----    ----     ----   ------  ----   ----
  1002KB DeflatN    226KB 77.5% 09/26/2005  3:16p a7f6d4e9 0777   M0511514944/file1
   474KB DeflatN     91KB 80.8% 09/26/2005  3:16p fbc1c376 0777   M0511514944/file2
   476KB DeflatN     91KB 80.9% 09/26/2005  3:16p 9fac9cf5 0777   M0511514944/file3
   113KB DeflatN     92KB 18.5% 09/26/2005  3:16p 5b5b5521 0777   M0511514944/file4
  ------           ------ -----                                   ----
  2065KB            500KB 75.8%                                      4

In perl I want to be able to do the following.

issue the following shell command.

pkipc test.zip 

which would result in something like

PKZIP(R)  Version 6.0  FAST!  Compression Utility for AIX
Copyright 1989-2002 PKWARE Inc.  All Rights Reserved. Registered Version
PKZIP Reg. U.S. Pat. and Tm. Off.  Patent No. 5,051,745

Viewing .ZIP: test.zip

  Length Method     Size  Ratio    Date     Time   CRC-32  Mode   Name
  ------ ------     ----  -----    ----     ----   ------  ----   ----
  1002KB DeflatN    226KB 77.5% 09/26/2005  3:16p a7f6d4e9 0777   M0511514944/file1
   474KB DeflatN     91KB 80.8% 09/26/2005  3:16p fbc1c376 0777   M0511514944/file2
   476KB DeflatN     91KB 80.9% 09/26/2005  3:16p 9fac9cf5 0777   M0511514944/file3
   113KB DeflatN     92KB 18.5% 09/26/2005  3:16p 5b5b5521 0777   M0511514944/file4
  ------           ------ -----                                   ----
  2065KB            500KB 75.8%                                      4

I need the take only the columns and values output by the pkzip command and add the constant "COMMENT ;" in front of it to make the following

COMMENT       ;  Length Method     Size  Ratio    Date     Time   CRC-32  Mode   Name
COMMENT       ;  ------ ------     ----  -----    ----     ----   ------  ----   ----
COMMENT       ;  1002KB DeflatN    226KB 77.5% 09/26/2005  3:16p a7f6d4e9 0777   M0511514944/file1
COMMENT       ;   474KB DeflatN     91KB 80.8% 09/26/2005  3:16p fbc1c376 0777   M0511514944/file2
COMMENT       ;   476KB DeflatN     91KB 80.9% 09/26/2005  3:16p 9fac9cf5 0777   M0511514944/file3
COMMENT       ;   113KB DeflatN     92KB 18.5% 09/26/2005  3:16p 5b5b5521 0777   M0511514944/file4
COMMENT       ;  ------           ------ -----                                   ----
COMMENT       ;  2065KB            500KB 75.8%                                      4

Finally I need the above appended to an existing log file.
Please advise me on how to achieve this using PERL. Thanks for your help.

Jerardfjay

pkipc test.zip |awk '"Length"==$1,0{print "COMMENT  ; " $0}' >>logfile

In Perl, something along the lines of

#!/usr/bin/perl 

$out = `pkzipc test.zip`;
$start = 0;
$buf = '';
foreach $line (split /\n/, $out) {
	if ($line =~ /^\s*Length/) { $start = 1; }
	if ($start) {
		$buf .= ('COMMENT   ; ' . $line . "\n");
	}
}
open FILE, ">>file.txt" or die "cannot open file for writing";
print FILE $buf;
close FILE;

Thanks cbkihong,

Its exactly what I was looking for. Although I understand the piece where you concatenate the string "COMMENT ;" to the existing lines after filtering unwanted lines, what is the logic that you are using to filter the lines that start with PKZIP,Copyright and Viewing?

The other question that I have is that how can I use a variable that holds the name of the logfile instead of hardcoding the line

open FILE, ">>file.txt" or die "cannot open file for writing";

Thanks for your help.
Jerardfjay

Just using the variable $LogFile that holds ths name of the logfile seems to do the trcik. Thanks.

There's no trick. Just find the line that contains "Length" and process those thereafter, so a sed run will do the same trick.

But a warning though. The routine will not notice if the command fails for whatever reason. Maybe you will want to check $? (if pkzipc obeys so) for return value, e.g.

$out = `pkzipc test.zip`;
if ($? >> 8) {
    # error (assume non-zero return status is error)
}

As a sidenote, did you try the Archive::Zip module (of course you will need to download and install it)? It seems to let you retrieve such information programmatically:

http://search.cpan.org/~smpeters/Archive-Zip-1.16/lib/Archive/Zip.pod\#Member\_Simple_accessors

Thanks cbikong. I was actually referring to my question of trying to use the variable name instead of the hardcode log file name in the line of code

open FILE, ">>file.txt" or die "cannot open file for writing";

Thanks for the Archive::Zip module for perl compression-decompression. However, like I have mentioned before, I would have to create my own perl environment in order to get this installed and have it working.
Moreover, there is logic in the original program to perform a pkzipc only when the contents of the zip file is greater than zero.

Thanks for your help.
Jerardfjay

Hi,

Back again. If I wanted to say filter the columns that I need in the output as follows how would I do it. Please advise. Thanks.

Output required

  Length Size  Ratio  Name
  ------ ----  -----  ----
  1002KB 226KB 77.5%  M0511514944/file1
   474KB  91KB 80.8%  M0511514944/file2
   476KB  91KB 80.9%  M0511514944/file3
   113KB  92KB 18.5%  M0511514944/file4
  ------ ------ ----- ----
  2065KB 500KB 75.8%  4

Code I have so far doesnt seem to work.

#!/usr/bin/perl 

$out = `pkzipc test.zip`;
$start = 0;
$buf = '';
$Count = 0;
foreach $line (split /\n/, $out) {
	if ($line =~ /^\s*Length/) { $start = 1; }
	if ($start) {
($Fld1,$Fld2,$Fld3,$Fld4,$Fld5,$Fld6,$Fld7,$Fld8,$Fld9) = split(' ', $line, 9999);
if ($Fld1 =~ '------') { $Count = $Count + 1; }
                                           if ($Count =~ 2) {
                                                $Newline = printf ("%6s %5s %5s %-200s\n", $Fld1, $Fld2, $Fld3, $Fld4);
                                              }
                                           else {
                                                $Newline = printf ("%6s %5s %5s %-200s\n", $Fld1, $Fld3, $Fld4, $Fld9);
                                              }
		$buf .= ('COMMENT   ; ' . $Newline . "\n");
	}
}
open FILE, ">>file.txt" or die "cannot open file for writing";
print FILE $buf;
close FILE

The desired output is not obtained with the code above. Can someone tell me whats wrong. Thanks for your help.
Jerardfjay

Try $Count == 2 on the next line.

Hi,

Back again. I got the code to work. Thanks cbkihong.
Here is the current snippet of the code.

$out = `pkzipc $CurDir$WorkDir\.zip`;
$start = 0;
$buf = '';
$Count = 0;
open FILE, ">>$CurDir$WorkDir\.ctr" or print ("Cannot open file ${WorkDir}\.ctr for writing $! \n");
foreach $line (split /\n/, $out)
{
      $Newline = '';
      ($Fld1,$Fld2,$Fld3,$Fld4,$Fld5,$Fld6,$Fld7,$Fld8,$Fld9) = split(' ', $line, 9999);
      if ($Fld1 =~ /^\s*Length/) { $start = 1; }
      if ($start)
         {
            if ($Fld1 eq '------') {
               $Count = $Count + 1;
            }
            if ($Count eq 2) {
               $Newline=sprintf "%6s %6s %5s %5s", $Fld1 , $Fld2 , $Fld3 , $Fld4;
               }
               else {
                  $Newline=sprintf "%6s %6s %5s %-200s", $Fld1 , $Fld3 , $Fld4 , $Fld9;
                  }
            $buf .= ('COMMENT          ; ' . $Newline . "\n");
          }
       }
       print FILE $buf;
       close FILE;

Here is the partial output that I get of the .ctr file

COMMENT          ; Text from this message will appear in the control file as instructions to the re
COMMENT          ; Length   Size Ratio Name

COMMENT          ; ------   ---- ----- ----

COMMENT          ; 1002KB  226KB 77.5% DIR1/M0511514944.exp

COMMENT          ;  474KB   91KB 80.8% DIR2/47105SNAAA120-C1__LEVERASSYHANDBRAKE__LD521117.exp

COMMENT          ;  476KB   91KB 80.9% DIR2/47105SNAAA830-C1__LEVERASSYHANDBRAKE__LD521117.exp

COMMENT          ;  113KB   92KB 18.5% OTHER_FILES/44732S0K_A003____C4426278.exp

COMMENT          ; ------ ------ -----  ----
COMMENT          ; 2065KB  500KB 75.8%     4

However I do get the following messages during execution.

Use of uninitialized value in pattern match (m//) at test.pl line 415, <IN> line 2.
Use of uninitialized value in pattern match (m//) at test.pl line 415, <IN> line 2.

Line 415 happens to be

if ($Fld1 =~ /^\s*Length/) { $start = 1; }

Any ideas as to how to overcome this message. Thanks. Jerardfjay

That means the line is empty. Confirm by print $line, is that line empty?

That is a warning. It is mostly harmless, but if you want to get rid of that, you can try to put

next unless (defined $Fld1);

before line 415, so that the iteration is skipped to check next line, after all the current one is empty.

thanks cbkihong.

I understand this is only a warning message. However I would like to get a clean execution, without warnings.

meaning when the $fld1 has no values or is blank, then this messages is generated.

thanks again for your help.
jerardfjay

Hello,

How do I trim/truncate the value of the field $Fld9 to lets say 10 characters wide. I need to only use the first left justified 10 characters. If there is more than 80 characters that are assigned to this field from the $line.

I have tried the following and it doesnt seem to make a difference.

$Newline=sprintf "%6s %6s %5s %.10s", $Fld1 , $Fld3 , $Fld4 , $Fld9;

instead of

$Newline=sprintf "%6s %6s %5s %-10s", $Fld1 , $Fld3 , $Fld4 , $Fld9;

However if the $Fld9 is being assigned a value more than 10 characters wide,
The sprintf statement does not seem to truncate the value while printing the line.

do I have to use another command for this or can is there an alternate formatting option that I can use to truncate field values while printing using sprintf in PERL.

Please advise. Thanks
Jerardfjay

Hello,

I have used substr($Fld9, 0, 10) to get the values that I need and while printing I use %-10s to left justify the value being printed.

Thanks
Jerardfjay