http://www.perlmonks.org?node_id=903868

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

Hi all

I'm converting a shell script to perl. The shell script has a number of switches passed to it, one being "-?".

Using "getopts" I can cater for all the various switches *except* the -?.

I can't use a variable '$opt_?' as it gives a syntax error.

I tried to list the various switches then use $ARGV[0}to pick up the -? if it was supplied, but having the '-', in front of the question mark, makes getopts look for a switch, rather than treating it as $ARGV[0}.

Is there any way I can pass "-?" as an option for getopts?

I'm calling the script via

script.pl -d -P MBKL107 -v name=fred -?
Removing the dash preceding the question mark in the command isn't an option, neither is using something other than "-?".

my $opt_z; our ( $opt_d,$opt_h,$opt_l,$opt_L,$opt_i,$opt_o,$opt_P,$opt_p,$opt_q,$ +opt_r,$opt_v,$opt_c ); $Getopt::Std::STANDARD_HELP_VERSION = 1; getopts('dhlLio:P:pqrv:c'); if ($ARGV[0]eq "-?") { $opt_z = $ARGV[0]; }

If I knew the "-?" would always be first I could put the check for -? in $ARGV[0} before the getops command, but I don't know what order the switches will be provided in so that's not an option either.

Also I don't have control over the command line so can't use a double dash on the command line to let the script know the options are finished and that -? is now $ARGV[0}

Any help your collective wisdom can offer up will be greatly appreciated.
Thanks Kev

Replies are listed 'Best First'.
Re: getopts and -?
by Anonymous Monk on May 10, 2011 at 01:19 UTC
    getopts('oif:', \%opts); # options as above. Values in %opts
    no strict 'refs'; warn local ${"opt_?"} = 6;
    use Getopt::Long; GetOptions( q!help|h|?! => \$help );
    $ perl -MGetopt::Long -e " my $help; GetOptions( q!help|h|?! => \$help + ); warn $help; " -- --help 1 at -e line 1. $ perl -MGetopt::Long -e " my $help; GetOptions( q!help|h|?! => \$help + ); warn $help; " -- -h 1 at -e line 1. $ perl -MGetopt::Long -e " my $help; GetOptions( q!help|h|?! => \$help + ); warn $help; " -- -? 1 at -e line 1. $ perl -MGetopt::Long -e " my $help; GetOptions( q!help|h|?! => \$help + ); warn $help; " -- -f Unknown option: f Warning: something's wrong at -e line 1.
      Thanks for both your help.

      I have now got it working aside of one issue.

      our ( $opt_d,$opt_h,$opt_l,$opt_L,$opt_i,$opt_o,$opt_P,$opt_p,$opt_q,$ +opt_r,$opt_v,$opt_c,$opt_z ); # 'L' =>\$opt_L, # 'p' =>\$opt_p, GetOptions ( 'd' =>\$opt_d, 'h' =>\$opt_h, 'l' =>\$opt_l, 'i' =>\$opt_i, 'o:s' =>\$opt_o, 'P:s' =>\$opt_P, 'q' =>\$opt_q, 'r' =>\$opt_r, 'v:s' =>\$opt_v, 'c' =>\$opt_c, 'help|?!' =>\$opt_z, );
      If I include both upper and lower case options L and P I end up getting the error message
      'Duplicate specification "L" for option "l"'

      Is there a way to parse both upper and lower case characters for the same letter?

      Appreciate your time and help.
        Oops..posted my version prior to reading your responses (honest i had got there off my own accord!) but like your versions, you both have "L & l" and "P & p" which getoptions doesn't seem to like, thinking they are duplicates.
Re: getopts and -?
by ikegami (Patriarch) on May 10, 2011 at 01:33 UTC

    Many shells treat "?" specially, so you may have to use

    script.pl -d -P MBKL107 -v name=fred '-?'

    Now that you're actually passing it to the script, you can use Getopt::Long to parse your args. Great module, and it handles "-?".

Re: getopts and -?
by kejohm (Hermit) on May 10, 2011 at 01:20 UTC

    Have a look at using the Getopt::Long module, specifically this.

    Update: Link fixed.

      Thank you for your response, however having looked at that, I can't see how I can combine the other options with the "help|?"

      I presume I need to define an $opt_help variable, but can't see how I can combine the

      getopts('dhlLio:P:pqrv:c');

      with

      #GetOptions ("help|?");

      patently

      GetOptions ("help|?dhlLio:P:pqrv:c");

      doesn't do it!

        The parameters passed to the Getopt::Long::GetOptions() function are different to the Getopt::Std::getopts() function. One way to call GetOptions() is to pass a hash with the keys specifying each option, and the values specifying a reference to a variable that will be set. Here is an example based on your code:

        our ( $opt_d,$opt_h,$opt_l,$opt_L,$opt_i,$opt_o,$opt_P,$opt_p, $opt_q,$opt_r,$opt_v,$opt_c,$opt_help ); GetOptions( 'd' => \$opt_d, 'h' => \$opt_h, 'l' => \$opt_l, 'L' => \$opt_L, 'i' => \$opt_i, 'o=s' => \$opt_s, 'P=s' => \$opt_P, 'p' => \$opt_p, 'q' => \$opt_q, 'r' => \$opt_r, 'v=s' => \$opt_v, 'c' => \$opt_c, 'help|?' => \$opt_help, );

        Since your code has a lot of options, you may want to look at storing the options in a hash, rather than individual variables. Check out the Getopt::Long manpage for more info.

        Getopt::Long doesn't work exactly like Getopt::Std, like I showed, so use
        GetOption( 'd=s' => $opt_d, # d 'h=s' => $opt_h, # h 'l=s' => $opt_l, # l 'L=s' => $opt_L, # L 'i=s' => $opt_i, # i 'o!' => $opt_o, # o: 'P!' => $opt_P, # P: 'p=s' => $opt_p, # p 'q=s' => $opt_q, # q 'r=s' => $opt_r, # r 'v!' => $opt_v, # v: 'c=s' => $opt_c, # c )
        or
        GetOption( %h,#values in %h 'd=s', # d 'h=s', # h 'l=s', # l 'L=s', # L 'i=s', # i 'o!', # o: 'P!', # P: 'p=s', # p 'q=s', # q 'r=s', # r 'v!', # v: 'c=s', # c )
        generated with
        #!/usr/bin/perl -- use strict; use warnings; Main( @ARGV ); exit( 0 ); sub Main { StdToLong('dhlLio:P:pqrv:c'); } BEGIN { my %Flags = ( #~ ':' => '', # boolean, default ':' => '!', # boolean, explicit, negatable '' => '=s', ); sub StdToLong { StdToLong1(@_); StdToLong2(@_); } sub StdToLong1 { print "GetOption(\n"; while( $_[0] =~ m/(\w)(\W)?/g ){ no warnings 'uninitialized'; print qq[ '$1$Flags{$2}' => \$opt_$1, # $1$2 \n]; } print "\)\n"; } sub StdToLong2 { print "GetOption( \%h,#values in %h\n"; while( $_[0] =~ m/(\w)(\W)?/g ){ no warnings 'uninitialized'; print qq[ '$1$Flags{$2}', # $1$2 \n]; } print "\)\n"; } } __END__