below_avg_st
below_avg_st

Reputation: 197

Perl passing command line arguments

I have a program that currently takes either 2 or 3 command line arguments find.pl [i] <perlRegexPattern> <listOfFiles>. Now the program will get through my if statements if I pass find.pl proj1 Data or find.pl -i proj1 Data, however I want to change it so that my program will accept something like find.pl -i ".*proj1.*" DataA/*, when I try to pass it my program doesn't make it past the 2nd if statement. I don't quite understand how to pass these as parameters and then use them in my program.

#!/usr/bin/perl -w
if(@ARGV < 2){
    print "\n2) Usage: find.pl [-i] <perlRegexPattern> <listOfFiles>\n\n";
    exit;
}
if(@ARGV > 3){
    print "\n3) Usage: find.pl [i] <perlRegexPattern> <listOfFiles>\n\n";
    exit;
}
if(@ARGV == 3 && $ARGV[0] ne "-i"){
    die "\n4) Usage: find.pl [i] <perlRegexPattern> <listOfFiles>\n\n";
}

if ($#ARGV eq 1 ){
    print "normal case\n";
    my ($pattern, $filelist) = @ARGV;
    print "$pattern $filelist\n";
    opendir( DIR , $filelist ) or die "\nCannot open directory $filelist\n\n";

    while ( ($fp = readdir(DIR)) ){
        if( $fp =~ m/$pattern/){
            print "$fp\n";
        }
        elsif( $fp =~ m/.*\.txt/){
            print "$fp is a text file\n";   #Still working on this part
            open( FILE, '<' , $fp) or die ("\nCould not open file $fp\n\n");
            while( <FILE> ){
                if($_ =~ m/$pattern/){
                    print "$fp : $_ : line pattern match\n";
                    last;
                }
            }
            close(FILE);
        }
    }
}
else{
    print "-i case\n";
    my ($pattern, $filelist) = @ARGV[1 .. 2];
    print "$pattern $filelist\n";
    #TODO
}

Upvotes: 0

Views: 470

Answers (2)

Richard RP
Richard RP

Reputation: 525

Take a look at the standard modules Getopt::Std and File::Find and note that you can save some open/close statements by using a localized @ARGV:

#!/usr/bin/perl -w

use strict;
use Getopt::Std;
use File::Find;

##  Parse option(s)
getopts 'i', \my %opt;

##  Show help
die <<usage unless @ARGV > 1;
Usage:
  $0 [options] pattern searchpaths...

Options:
  -i    Case insensitive search
usage

##  Compile regex
my $re = shift;
if ($opt{i}) { $re = qr($re)i }
else         { $re = qr($re) }

##  Walk searchpaths
find (sub
  {
    ##  Filename matches the regex
    if (/$re/)
    {
      printf "match name:    %s\n", $File::Find::name
    }
    ##  File is regular, name ends with .txt, and...
    elsif (-f and /\.txt$/)
    {
      local @ARGV = $_;
      while (<>)
      {
        ##  ... a line in the file matches the regex.
        chomp;
        /$re/ 
          and printf "match content: %s: %s\n", $File::Find::name, $_
          and last;
      }
    }
  },
  @ARGV);

Example:

find.pl -i ^fa /usr/share/doc/lighttpd

Output:

match name:    /usr/share/doc/lighttpd/fastcgi-state.txt
match name:    /usr/share/doc/lighttpd/fastcgi.txt
match content: /usr/share/doc/lighttpd/security.txt: FastCGI
match content: /usr/share/doc/lighttpd/accesslog.txt: fastcgi + chroot
match content: /usr/share/doc/lighttpd/performance.txt: failed'. This is very rare and might only occur in test setups.

Upvotes: 1

Sobrique
Sobrique

Reputation: 53478

Your problem here is - the shell expands the wildcards before your perl script gets to them.

Try adding:

use Data::Dumper;
print Dumper \@ARGV;

And you'll see what's getting passed into your program.

Given you're using wildcards, it's likely it'll match more than one thing - and if it does, then your program will be receiving additional arguments. Only your program will only accept 3.

Upvotes: 1

Related Questions