sock has asked for the wisdom of the Perl Monks concerning the following question:

This is my first script. I created it to change any files that have the '_' character to a single space in a given directory. I'm using regex to select the files and a simple foreach statement to sift through the given files but how would i be able to pass arguments and have defaults for those not passed?
~ Nick
#!/usr/bin/perl -ws use strict; my $oggdir = '/media/tmp/'; chdir $oggdir or die "can't chdir to $oggdir: $!\n\n"; opendir(DIR, $oggdir) or die "can't open $oggdir for read: $!\n\n"; my @files = grep { /.*_+.*\.[Oo][Gg]{2}$/ } readdir(DIR); closedir(DIR) or warn "error closing $oggdir: $!\n\n"; foreach ( @files ) { my @chars = split(/_+/, $_); my $final=join(" ", @chars); print "Original: $_ \n"; print "New: $final \n"; rename $_, $final; print "Conversion Complete.\n"; }

Replies are listed 'Best First'.
Re: Using arguements and defaults
by Roger (Parson) on Nov 24, 2003 at 05:52 UTC
    Do you mean pass command-line arguments? If so, checkout the module Getopt::Long. Otherwise, are you looking for something like below?
    #!/usr/bin/perl -w use strict; use IO::Dir; my $oggdir = '/media/tmp/'; ParseDirectory($oggdir); sub ParseDirectory { my $dir = shift; my $d = IO::Dir->new($dir) or die "Can not open directory $dir for read!"; while (defined(my $f = $d->read)) { if ($f =~ /.*_+.*\.[Oo][Gg]{2}$/) { # matching files my $new_name = $f; $new_name =~ s/_//; # remove _ # rename $f to $new_name, etc. } else { # non-matching files # do whatever, set to default, etc. } } }
    And an example of using Getopt::Long to parse command-line arguments:
    #!/usr/local/bin/perl -w use strict; use Getopt::Long; # Parse command line arguments and assign corresponding variables GetOptions ( 'i|init=s' => \( my $INIT = undef ), # Specify the root director +y 'u|upload' => \( my $UPLOAD = undef ), 'v|verbose' => \( my $VERBOSE = 0 ), ); unless ( defined $INIT ) { print <<EOF Kapiti Exception Report Usage: $0 [options] Options: -i|--init [file] Specify the path to initialization file -u|--upload Upload the result into database -v|--verbose Let the report generator print more information EOF ; exit(1); } # continue on...
Re: Using arguements and defaults
by sgifford (Prior) on Nov 24, 2003 at 05:49 UTC

    Arguments are in the list @ARGV. So if you want to set $oggdir to the first argument, or to /media/tmp if there is no first argument, you could do something like:

    my $oggdir; if ($ARGV[0]) { $oggdir=$ARGV[0]; } else { $oggdir='/media/tmp'; }

    A shorter and more idiomatic way to do the same thing is:

    my $oggdir = shift || '/media/tmp';
    shift removes the first item from a list and returns it; in the main body of a program (outside of subs), it defaults to using @ARGV. So this is a little different than the above; it will remove the first argument from @ARGV. If shift returns an argument, $oggdir will be set to it; otherwise it will use the other half of the or, and set it to the default value.

    If you want more complex argument processing, try using Getopt::Std or Getopt::Long.

Re: Using arguements and defaults
by vladdrak (Monk) on Nov 24, 2003 at 06:13 UTC
    How about something like:
    #!/usr/bin/perl use strict; # @ARGV is = to @_ by default my $path=shift or die "Usage: $0 <directory|file>\n"; # Is it a directory or a file? if (-d $path) { opendir(DIR,$path) or die "could not open $path: $!\n"; for my $file (readdir(DIR)) { if ($file =~ /\_/) { nounder($file); } } closedir(DIR); } else { nounder($path); } sub nounder { my $file=shift; my $newfile=$file; $newfile=~s/\_/ /g; rename($file,$newfile) or die "couldn't rename $file: $!\n"; print "renamed $file to $newfile\n"; }
    -vladdrak

      @ARGV is != to @_! It's just that shift works differently in the main file's scope.

      See perldoc -f shift and perldoc perlvar.

Re: Using arguments and defaults
by Roy Johnson (Monsignor) on Nov 24, 2003 at 17:49 UTC
    Just a couple of notes:
    /.*_+.*\.[Oo][Gg]{2}$/
    should probably be
    /_+.*\.ogg$/i
    And your use of split and join to replace the _ would be better done with
    tr/_/ /s;