Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

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 (Canon) 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
[marto]: good morning all, TCIF
[Discipulus]: TCIF & chips marto! and sane dots too
[Corion]: Hi marto ;) All Hail Crunchy!
[Corion]: marto:I hope you're well

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (8)
As of 2017-02-24 09:48 GMT
Find Nodes?
    Voting Booth?
    Before electricity was invented, what was the Electric Eel called?

    Results (353 votes). Check out past polls.