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

Hi Monks

I have a perl script that accepts the following command line syntax in Linux:

./script.pl -file myfile.txt -file yourfile.txt -file ourfile.txt

My code looks like this:

#!/usr/bin/perl use strict; use warnings; use Getopt::Long qw (GetOptions); my (@Files); Getopt::Long::Configure("no_ignore_case", "prefix_pattern=(--|-|\/)"); GetOptions ("file=s@" => \@Files); foreach (@Files) { #Do stuff with file print "$_\n"; }
Prints:
myfile.txt yourfile.txt ourfile.txt

When I try and run the following command though, it only returns the first filename (myfile.txt).

./script.pl -file *.txt

Why does this happen and how can I get my script to accept wild card characters?

Replies are listed 'Best First'.
Re: Getopt Long and processing arrays from Linux shell
by Anonymous Monk on Jun 21, 2007 at 09:22 UTC
    Several things here: First, you are not passing an array from the shell, shell arrays are variables that cannot be exported, except to another shell of the same type.
    The "wild card" characters are not passed into your script, they are expanded by the shell. You are actually passing into your script -file myfile.txt yourfile.txt ourfile.txt, there is no "-file" at the front of each one. On Bash or Ksh use 'set -x' to see the effect.
    If you want to pass in '*.txt' from the shell, put it in quotes: ./script.pl -file '*.txt'. However, unless you are calling glob your script will look for a file called '*.txt'. Which probably is not what you want. Why bother with the -file option and Getopts if all you want is a list of filenames?

      Thanks for the reply.

      The short reason I'd like to use the -file option is because the txt files are actually backup files for a MySql db. The user wants to specify which files he'd like to restore(a function which the script already does).

      So instead of specifying each file for the whole month of June in one command, he could rather say -file 2007-06-*.txt... or similiar.
      Seeing that this can't work, do you have any ideas what I can do?

        Two possible solutions:

        The first one involves making the correct expansion in the call:

        perl ./script.pl $(ls *.txt | sed 's/^/-file /')

        This converts the call to:

        perl ./script.pl -file myfile.txt -file yourfile.txt -file ourfile.txt

        But this is ugly, isn't it?

        Another solution is to do the expansion inside of the script:

        #!/usr/bin/perl use strict; use warnings; use Getopt::Long qw (GetOptions); my (@Files); Getopt::Long::Configure("no_ignore_case", "prefix_pattern=(--|-|\/)"); GetOptions ("file=s@" => \@Files); my @globs = map {glob ($_)} @Files; print "glob: $_\n" for @globs;

        Now you can call the script like:

        ./script.pl -file "*.txt"

        And get the expected output. The quotes in the call arount *.txt are needed to prevent the expansion in the shell prior to the actual call to the script.

        HTH

        citromatik

        What about ommiting the -file option alltogether and using all non-option arguments in @ARGV as file names?
Re: Getopt Long and processing arrays from Linux shell
by Anonymous Monk on Aug 09, 2011 at 12:57 UTC

    How about taking advantage of :

    "Options can take multiple values at once, for example...
    This can be accomplished by adding a repeat specifier to the option specification.
    Repeat specifiers are very similar to the {...} repeat specifiers that can be used with regular expression patterns
    .... It is also possible to specify the minimal and maximal number of arguments an option takes.
    foo=s{2,4} indicates an option that takes at least two and at most 4 arguments.
    foo=s{,} indicates one or more values; foo:s{,} indicates zero or more option values."

    #!/usr/bin/perl use strict; use warnings; use Getopt::Long qw (GetOptions); my (@Files); Getopt::Long::Configure("no_ignore_case", "prefix_pattern=(--|-|\/)"); GetOptions ("file=s{,}" => \@Files); foreach (@Files) { #Do stuff with file print "$_\n"; }