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

Been a bit of time since I've worked in perl, but I used to use GetOpts::STD pretty frequently. Trying again can't seem to get it to work. Here's the code:
use Getopt::Std; # declare the perl command line flags/options we want to allow my %opts; getopts('f:', %opts); # test for the existence of the options on the command line. if ($opts{f}) { my $file eq $opts{f}; print "$file\n"; }
If I execute "./myscript.pl -f foo.bar", I get nothing returned, as though the $opts{f} is empty. Sure I'm missing something simple. Can one of you Monks help me out? Thanks

Replies are listed 'Best First'.
Re: GetOpts not working:
by MidLifeXis (Monsignor) on Dec 08, 2015 at 18:24 UTC

    I believe that Getopt::Std requires a hashref to the options, not the hash itself.

    getopts('f:', \%opts);

    --MidLifeXis

Re: GetOpts not working:
by kcott (Archbishop) on Dec 08, 2015 at 18:26 UTC

    G'day finfan,

    You need to change the hash argument

    getopts('f:', %opts);

    to a hashref argument

    getopts('f:', \%opts);

    As shown in the Getopt::Std documentation.

    — Ken

      Thanks, the was it.
Re: GetOpts not working:
by stevieb (Canon) on Dec 08, 2015 at 18:29 UTC

    You've got two issues... first, getopts() requires you to specify a reference to a hash, not a hash directly (change %opts to \%opts in the getopts() call). Second, you're trying to assign $opts{f} to $file, but you're comparing with eq instead. Change eq to =. Here's the full code with fixes:

    use Getopt::Std; # declare the perl command line flags/options we want to allow my %opts; getopts('f:', \%opts); # test for the existence of the options on the command line. if ($opts{f}) { my $file = $opts{f}; print "$file\n"; }
      Thanks stevieb. I realized the comparison operator there after the hash was pointed out.
Re: GetOpts not working:
by james28909 (Deacon) on Dec 09, 2015 at 09:33 UTC
    Without using any modules.
    use strict; use warnings; use v5.16; my $infile; my $outfile; if ($#ARGV <= 2 || $#ARGV >= 4){ die "Silly you, there are an incorrect amount of args :)\n" } for ( 0 .. $#ARGV / 2 ) { my $switch = shift(@ARGV); my $value = shift(@ARGV); given ($switch) { when ('-f1') { $infile = $value } when ('-f2') { $outfile = $value } } } print "Infile: $infile\n", "Outfile: $outfile";
    Update: changed 'if ($#ARGV % 2 == 0)' to 'if ($#ARGV <= 2 || $#ARGV >= 4)'

      From which it can be seen that there is some virtue in using modules, especially when they are core! Code is:

      • generally clearer
      • easier to maintain
      • more likely to work first time
      • shorter
      • easier to write tests for

      And modules generally have decent documentation with examples and save rewriting wheels badly.

      Premature optimization is the root of all job security

        with examples and save rewriting wheels badly.

        Ah, the old subliminal hint ;) haha. I def understand what you mean though, I was just giving an example :)

      As long as experimental feature warnings are not a concern.

      --MidLifeXis

      Here's a similar way, but instead of using the experimental switch, I use a dispatch table. Note this destroys @ARGV in the process and definitely is only an example and shouldn't be used in production code without much more work.

      use warnings; use strict; my ($file, $thing); my %arg_table = ( -f => sub { $file = shift; }, -t => sub { $thing = shift; }, default => sub { die "bad param"; }, ); while (my @args = splice @ARGV, 0, 2){ if (defined $arg_table{$args[0]}){ $arg_table{$args[0]}->($args[1]); } else { $arg_table{default}->(); } } print $file if defined $file; print $thing if defined $thing;
      Heres another way:
      use strict; use warnings; my @ARGV = qw(-infile data_in.bin -outfile data_out.bin); my %args; for ( 0 .. $#ARGV / 2 ) { my $switch = shift(@ARGV); my $value = shift(@ARGV); $args{$switch} = $value; } print "Infile: $args{-infile}\n", "Outfile: $args{-outfile}" if ( exis +ts $args{-infile} && exists $args{-outfile} );
      I am growing to really like hashes, and I think im about ready to start doing like hash of arrays, so i can have multiple values for a single hash key. Isnt that how this works?
      my %hash = { key => [value_1, value_2, value_3, value_4]};
      I just wonder how i would print all the values
      Edit: I figured it out, thanks

        There appears to be no benefit to your use of a for loop in that code. Standard hash population means that it isn't needed.

        use strict; use warnings; my @ARGV = qw(-infile data_in.bin -outfile data_out.bin); my %args = @ARGV; print "Infile: $args{-infile}\n", "Outfile: $args{-outfile}" if ( exis +ts $args{-infile} && exists $args{-outfile} );

        works just the same. HTH.

        PS. I wouldn't use @ARGV for a lexical variable name since it ordinarily has a special meaning.