Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Perl Input Parameters for Unix

by Anonymous Monk
on Jul 09, 2012 at 15:41 UTC ( #980707=perlquestion: print w/replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have the following code that parses an input file and outputs a .stat file and a .csv file. I would like to pass the following input parameters:

-i input filename (instead of having it hard-coded) -s output .stat file (to a certain location) -o output .csv file (to a certain location)

I have not worked with input parameters before. What is the best way of setting this up? Thank you

# This program parses a error_log for necessary information and output +s a CSV file with the highest busy value for each 5 minute interval. + # The program also outputs a STAT file with the last 5 minute interval + of the CSV. use strict; use warnings; # Ignore theses values my %ignorables = map { $_ => 1 } qw([notice mpmstats: rdy bsy rd wr ka + log dns cls bsy: in); # Open the error log - Change the name of the file as needed. open my $error_fh, '<', 'iset_error_log'; # Subroutine to pull the line containing AP22,SM22, and Apache stats sub findLines { my($item,@result)=(""); # Iterates over the lines in the file, putting each into $_ while (<$error_fh>) { # Select only those fields that have the word 'notice' if (/\[notice/) { # Place those lines with the word 'rdy' on the next line if (/\brdy\b/){ push @result,"$item\n"; $item=""; } else { $item.=","; } # Split the line into fields, separated by spaces, skip th +e %ignorables my @line = grep { not defined $ignorables{$_} } split /\s+ +/; # More cleanup s/|^\[|notice|[]]//g for @line; # remove unnecessary eleme +nts from the array # Output the line. @line = join(",", @line); s/,,/,/g for @line; map $item.=$_, @line; } } @result } # Place the subroutine contents into an array my @array = &findLines; my $line; # Create an subroutine to place the contents of AP22, SM22, and Apache + in the correct order sub Program{ my @return = (); chomp @array; my ($dow,$mon,$day,$time,$year,$rdy,$bsy,$rd,$wr,$ka,$log,$dns,$cl +s,$dow2,$mon2,$day2,$time2,$year2,$val1,$mod1,$val2,$mod2,$val3,$mod3 +,$ap22,$sm22,$apache); foreach $line (@array){ ($dow,$mon,$day,$time,$year,$rdy,$bsy,$rd,$wr,$ka,$log,$dns,$cls,$ +dow2,$mon2,$day2,$time2,$year2,$val1,$mod1,$val2,$mod2,$val3,$mod3) = + ((split /[,]/, $line),("")x24); $line = "$dow,$mon,$day,$time,$year,$rdy,$bsy,$rd,$wr,$ka,$log,$dn +s,$cls"; # For lines with no variables if ($mod1 eq ""){ $line = $line.","."0".","."0".","."0"; } # For lines with only SM22 if ($mod1 eq "mod_sm22.cpp" && $mod2 eq ""){ $line = $line.",".$val1.","."0".","."0"; } # For lines with only AP22 if ($mod1 eq "mod_was_ap22_http.c" && $mod2 eq "" && $mod3 eq ""){ $line = $line.",".$val1.","."0".","."0"; } # For lines with AP22-SM22-Apache if ($mod1 eq "mod_was_ap22_http.c" && $mod2 eq "mod_sm22.cpp" && $ +mod3 eq "ApacheModule.cpp"){ $line = $line.",".$val1.",".$val2.",".$val3; } # For lines with SM22-AP22-Apache if ($mod1 eq "mod_sm22.cpp" && $mod2 eq "mod_was_ap22_http.c" && $ +mod3 eq "ApacheModule.cpp"){ $line = $line.",".$val2.",".$val1.",".$val3; } # For lines with AP22-SM22 if ($mod1 eq "mod_was_ap22_http.c" && $mod2 eq "mod_sm22.cpp" && $ +mod3 eq ""){ $line = $line.",".$val1.",".$val2.","."0"; } # For lines with SM22-AP22 if ($mod1 eq "mod_sm22.cpp" && $mod2 eq "mod_was_ap22_http.c" && $ +mod3 eq ""){ $line = $line.",".$val2.",".$val1.","."0"; } # For lines with SM22-Apache if ($mod1 eq "mod_sm22.cpp" && $mod2 eq "ApacheModule.cpp" && $mod +3 eq ""){ $line = $line.","."0".",".$val2.",".$val2; } # For lines with AP22-Apache if ($mod1 eq "mod_was_ap22_http.c" && $mod2 eq "ApacheModule.cpp" +&& $mod3 eq ""){ $line = $line.",".$val1.","."0".",".$val2; } # Push the array out of the subroutine ($dow,$mon,$day,$time,$year,$rdy,$bsy,$rd,$wr,$ka,$log,$dns,$cls,$ +ap22,$sm22,$apache) = ((split/[,]/, $line),("")x16); push @return, ("$line\n"); } return @return; } # Initialize the hashes my %interval; my %month; @month{qw/ jan feb mar apr may jun jul aug sep oct nov dec +/} = '01' .. '12'; # Put the contents of the subroutine into an array my @finalArray = &Program; # Delete the first line of the array $finalArray[0] = ""; # Create a new array without the first line my @lastArray = @finalArray; # Initialize CSV file and STAT file and print the header for the CSV f +ile open my $fh, ">", 'log_5min.csv' or die $!; print $fh "Time Interval,rdy,bsy,rd,wr,ka,log,dns,cls,ap22,sm22,apache +\n"; open my $FILE, ">", 'last_5min.stat' or die $!; # Select only those lines with the highest busy count in each 5 minute + interval my @maxima; for my $record (@lastArray) { my @fields = $record =~ /([^,\s]+)/g; next unless @fields; my @range = @fields[1..4]; $range[2] =~ s|(\d+):\d\d$|5*int($1/5)|e; my $range = join ' ', @range; my $value = $fields[5]; my ($dow, $mon, $day, $time, $year, $rdy, $by, $rd, $wr, $ka, $log +, $dns, $cls, $ap22, $sm22, $apache) = split /[,]/, $record; my $record2 = "$range,$rdy,$by,$rd,$wr,$ka,$log,$dns,$cls,$ap22,$s +m22,$apache"; if (@maxima == 0 or $range ne $maxima[-1][0]) { push @maxima, [$range, $value, $record2]; } else { @{$maxima[-1]}[1,2] = ($value, $record2) if $maxima[-1][1] > $ +value; } } # Print the contents to the CSV file print $fh $_->[2] for @maxima; # Print the last line to the STAT file my $string = (); $string = $_->[2] for $maxima[-1]; my ($timeStamp, $rdy, $by, $rd, $wr, $ka, $log, $dns, $cls, $ap22, $sm +22, $apache) = split /[,]/, $string; print $FILE "<ED>$by</ED>\n<ECO>Max Busy</ECO>\n<ECE></ECE>";

Replies are listed 'Best First'.
Re: Perl Input Parameters for Unix
by monsoon (Pilgrim) on Jul 09, 2012 at 15:49 UTC
      OP: Different people prefer different approaches, but I recommend Getopt::Long over Getopt::Std, et al. I like being able to use more than just a single letter for the flags to increase readability. Also, you can still abbreviate to a single letter (or unique fragment) to reduce typing when calling the script from the CLI. Another tip: you can set default, overridable values by defining (rather than just declaring) before the Getopts block for whichever variables you want defaults.
Re: Perl Input Parameters for Unix
by aitap (Deacon) on Jul 09, 2012 at 16:11 UTC
    Other than processing options using Getopt::Long (which I use most frequently) and Getopt::Std, options can be parsed manually. For example, in your case:
    my ($input,$stat,$csv); while (my $arg = shift @ARGV) { if ($arg eq "-i") { $input = shift @ARGV; } elsif ($arg eq "-s") { $stat = shift @ARGV; } elsif ($arg eq "-o") { $csv = shift @ARGV; } else { die "$arg: invalid argument\n"; } defined $input && defined $csv && defined $stat || die "You should def +ine -i, -o and -s!\n";
    You can also use 5.010 and process arguments in "switch-case" style.
    Sorry if my advice was wrong.
      When you parse the options manually, you'll also have to manually deal with multiple single letter options bundled into one argument. Something like -abc - that's 3 switches "a", "b" and "c". In fact "c" can even have an argument. You don't have to worry about any of this stuff with Getopt::Std.

      Could you explain in detail how this works exactly? Thank you

        This can work because there is an array called @ARGV, which contains all the command line arguments passed to the perl script (not to the perl itself). See perlvar for more.

        `shift` removes and returns the first element of this array, until none are left (when array is empty, it returns undef), so this `while` loop checks all the command line arguments from left to right (additional `shift`s inside the loop are used to get the parameter next to being processed now). See shift for more.

        Sorry if my advice was wrong.
Re: Perl Input Parameters for Unix
by kcott (Chancellor) on Jul 10, 2012 at 06:20 UTC

    In general, I'd recommend using a module such as one of those already described.

    For a quick-and-dirty script, where all options take values like the ones you've described, you can slurp @ARGV into a hash:

    #!/usr/bin/env perl -l use strict; use warnings; my %opt = @ARGV; print qq{Option $_ = }, $opt{$_} for sort keys %opt; print qq{-z option detected: $opt{-z}} if exists $opt{-z};

    Example runs:

    $ -i infile -o outfile -s statfile Option -i = infile Option -o = outfile Option -s = statfile $ -i infile -o outfile -s statfile -z zzzzzzzz Option -i = infile Option -o = outfile Option -s = statfile Option -z = zzzzzzzz -z option detected: zzzzzzzz

    -- Ken

Re: Perl Input Parameters for Unix
by cheekuperl (Monk) on Jul 09, 2012 at 15:58 UTC
    So all you wish to know is how to parse input parameters. Rest of the code you posted does not matter :)
    You can also try parsing them manually using @ARGV.
    Something like
    if ( $ARGV[0] eq "-i" ) { #do something with $ARGV[1] }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://980707]
Approved by marto
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2017-09-19 21:11 GMT
Find Nodes?
    Voting Booth?
    During the recent solar eclipse, I:

    Results (229 votes). Check out past polls.