使用Getopt模块从命令行读取参数
2013-02-24 14:47:15 阿炯

在 Linux/Unix 中为命令传入参数有二种形式:
长参数:--help
短参数:-h

也就是'-'和'--'的分别,'--'表示完整参数,'-'表示简化参数,在 Perl 的这个模块中也支持这二种方法。向Perl脚本传参最简单的做法是在脚本里使用'@ARGV'方法来取得,但这种方式可控性不好,有些时候会导致歧义。在这要介绍的Getopt模块实际上有二个模块:一个叫 Getopt::Long,另一个叫 Getopt::Std。

Getopt::Std模块的介绍:

Processes single-character, command-line options with option clustering. Exports two functions, which analyze @ARGV, extract information about the options, and return this information to your program in a set of variables. Processing of @ARGV stops when an argument without a leading - is encountered, if that argument is not associated with a preceding option. Otherwise, @ARGV is processed to the end and left empty.

getopt
getopt('switches'[, \%opts])

switches is a string of the command-line options that take arguments. For each option, getopt sets $opt_x (in which x is the switch) to the value entered as an argument. If \%optsis specified, it is a reference to a hash in which getopt sets the key to the name of the switch and the value to the argument (and the $opt_ variables are not set).

getopts    
getopts('switches'[, \%opts])

Like getopt, except that all valid options are included in switches, and options that take an argument are followed by a colon (:). For example:
getopt('oDI')    # -o, -D, & -I take arguments; there may
 # be other options
getopts('o:DI')  # -o, -D, and -I are the only valid
 # options; only -o takes an argument

\%opts means the same as with getopt.

初始设置:
use Getopt::Std;
use vars qw($opt_d $opt_f $opt_p);
getopts('d:f:p');

#注意上两行的参数要对应
[解释一下"d:f:p",d和f后有冒号,表示-d,-f后面要跟参数。p后面没有冒号,表示-p后面不带参数。而且-d,-f后所跟的参数分别赋给变量$opt_d和$opt_f。对于变量$opt_p,若命令行加了-p,则$opt_p=1,否则为0]

示例:
cat file.pl
use Getopt::Std;
use vars qw($opt_d $opt_f $opt_p);
getopts('d:f:p');
 
print "\$opt_d => $opt_d\n" if $opt_d;
print "\$opt_f => $opt_f\n" if $opt_f;
print "\$opt_p => $opt_p\n" if $opt_p;


然后在命令行中运行:
perl file.pl -d 20121018 -f freeoa -p

可得到下列形式的输出:
$opt_d =>20121018
$opt_f =>freeoa
$opt_p =>1

Getopt::Std模块用起来较为简单,当然除了Getopt::Std模块外。还有Getopt::Long模块,下面就介绍它的使用方法。


仿命令传参的用法

if( $ARGV[0] eq '-h' || $ARGV[0] eq '-help'){
help();
exit;
}

sub help {print "My help blah blah blah\n";};

########################################################
# USAGE
#
my $USAGE =<<USAGE;
     Usage:
         foo [ -baz -fu <bar>] [-help]
         where:
             baz: yadda, yadda, yadda
             freeoa: yadda, yadda, yadda
           help: Prints out this helpful message
USAGE
#
######################################################


Then, in my program, I could do this:
if ($help) {
  print "$USAGE\n";
  exit 0;
}


Getopt::Long介绍:
Provides two functions: GetOptions and config.

config
Getopt::Long::config(optionlist)
Sets the variables in optionlist to change the default behavior of GetOptions. The following options are available:

$Getopt::Long::autoabbrev
If true, option names can be invoked with unique abbreviations. Default is 1 (true) unless the environment variable POSIXLY_CORRECT has been set.

$Getopt::Long::getopt_compat
If true, options can start with +. Default is 1 unless the environment variable POSIXLY_CORRECT has been set.

$Getopt::Long::order
Value indicates whether options and non-options may be mixed on the command line:
$PERMUTE
Non-options may be mixed with options. The default if POSIXLY_CORRECT is not set.

$REQUIRE_ORDER
Mixing is not allowed. The default if POSIXLY_CORRECT is set.

$Getopt::Long::ignorecase
If true, ignore case when matching options. Default is 1.

$Getopt::Long::VERSION
The version number of this Getopt::Long implementation in the format major.minor.

$Getopt::Long::error
Internal error flag. May be incremented from a callback routine to cause options-parsing to fail.

$Getopt::Long::debug
If true, enables debugging output. Default is 0 (false).

GetOptions
$result = GetOptions(option-descriptions)

Uses descriptions from option-descriptionsto retrieve and process the command-line options with which your Perl program was invoked. The options are taken from @ARGV. After GetOptions has processed the options, @ARGV contains only command-line arguments that were not options. Returns 0 if errors are detected. Each option description consists of two elements:

Option specifier
Defines the option name and optionally a value as an argument specifier.

Option linkage
A reference to a variable that is set when the option is present.

GetOptions can also take as a first argument a reference to a hash that describes the linkage for the options. The linkage specified in the argument list takes precedence over the one specified in the hash. Thus, the following are equivalent:
%optctl = (size => \$offset);
&GetOptions(\%optctl, "size=i");

and:
&GetOptions("size=i" => \$offset);

Option specifiers
Each option specifier consists of an option name and possibly an argument specifier. The name can be a name, or a list of names separated by |; the first name in the list is the true name of the option, and the others are treated as aliases. Option names may be invoked with the shortest unique abbreviation. Values for argument specifiers are:

<none>
Option takes no argument. The option variable is set to 1.

!
Option does not take an argument and may be negated, that is, prefixed by no.

=s
Option takes a mandatory argument that is a string that will be assigned to the option variable. Even if the argument starts with - or --, it is assigned to the option variable rather than treated as another option.

:s
Option takes an optional string argument. If the option is invoked with no argument, an empty string ("") is assigned to the option variable. If the argument starts with - or --, it is treated as another option rather than assigned to the option variable.

=i
Option takes a mandatory integer argument, which may start with - to indicate a negative value.

:i
Option takes an optional integer argument that may start with - to indicate a negative value. With no argument, the value 0 is assigned to the option variable.

=f
Option takes a mandatory floating-point argument that may start with - to indicate a negative value.

:f
Option takes an optional floating-point argument that may start with - to indicate a negative value. With no argument, the value 0 is assigned to the option variable.

A hyphen (-) by itself is considered an option whose name is the empty string. A double hyphen (--) by itself terminates option processing. Any options following the double hyphen remain in @ARGV when GetOptions returns. If an argument specifier ends with @ (e.g., =s@), then the option is treated as an array.

The special option specifier <> can be used to designate a subroutine to handle non-option arguments. For this specifier to be used, the variable $Getopt::Long::order must have the value of the predefined and exported variable, $PERMUTE. See the description of Getopt::Long::config below.

Linkage specification

The linkage specifier can be a reference to any of the following:

Scalar
The new value is stored in the referenced variable. If the option occurs more than once, the previous value is overwritten.

Array

The new value is appended (pushed) onto the referenced array.

Subroutine
The referenced subroutine is called with two arguments: the option name, which is always the true name, and the option value.

If no linkage is explicitly specified, but a hash reference is passed, GetOptions puts the value in the hash. For array options, a reference to an anonymous array is generated.

If no linkage is explicitly specified, and no hash reference is passed, GetOptions puts the value into a global variable named after the option, prefixed by opt_. Characters that are not part of the variable syntax are translated to underscores. For example, --fpp-struct-return sets the variable $opt_fpp_struct_return.

初始化 Perl命令行中所接受的参数,简化了命令行参数的解析。
use Getopt::Long;
my @libs=();
my %flags=();
my ($verbose, $more, $diam, $debug, $test, $step);

GetOptions(
 'verbose+' => \$verbose,
 'more!' => \$more,
 'debug:i' => \$debug,
 'lib=s' => \@libs,
 'flag=s' => \%flags,
 'test|t' => \$test,
);

### $verbose
### $more
### $debug
### $test
### @libs;
### %flags


下面是详细解释,注意看 GetOptions 中的 => 前面的部分,下面是详解:
‘verbose+’  接有 + 的选项不接收变量,后面不需要加内容.直接使用就行了,会在每次出现时增加一次变量,就是讲命行时在参数中 -verbose -verbose 出现二次时 verbose 的值就会变成 2.

‘more!’  接有 ! 的选项不接收变量(也就是讲后面不需要加参数 –more 来使用就行了),只要命令行中出现了这个参数,就会默认是 1 ,是用来设置打开和关掉一个功能的>.可以在参数前加 no 变成负的例如-nomore.

‘flag=s’ 接有 = 的字符串要求接字符串(s)、整数(i),或者浮点(f)等类型的变量.

‘debug:i’ 接有 : 的选项会接受缺省为0或者为空字符串的可选变量.

‘test|t’ 接有 | 的选项表示可以给 –test 简写为 -t.

‘lib=s’ => @libs    如果相关联的变量是个数组, 如这个地方的 @libs, 那么选项可以多次出现, 值可以被推到数组里.

‘flag=s’ => %flags  如果相关联的变量是个散列, 那么就要求一个键=值(key=value)对, 并被插入到散列里.

备注:在匹配参数名的时候,GetOptions 在缺省设置下会忽略大小写,默认参数被简写为唯一的最短字符串(首字母).(例如:-m 代表 -more. 相同的首字母时,会加上第二个字母来区分)

示例如下:
# getopt.pl --verbose --verbose -v --more  --lib='/lib' -l '/lib64' --f a=1 --flag b=2  --debug 2 -t hto
### $verbose: 3
### $more: 1
### $debug: 2
### $test: 1
### @libs: [
###          '/lib',
###          '/lib64'
###        ]
### %flags: {
###           a => '1',
###           b => '2'
###         }


Getopt 模块的简单总结
1. 带值参数传入程序内部
※参数类型:整数, 浮点数, 字串
GetOptions(
 'tag=s' => \$tag
);

‘=’表示此参数一定要有参数值, 若改用’:'代替表示参数不一定要有参数值
‘s’表示传递字串参数, 若为’i'表传递整数参数, 若为’f'表传递浮点数.

带值参数使用的方法
$ test.pl --tag=string
$ test.pl --tag string

2. 需要传送多个值的参数到程序中.
比如需要传几个值到 @libfiles 中的操作方法.
GetOptions ("library=s" => \@libfiles);
GetOptions ("library=s@" => \$libfiles);

参数传到 @$tag
使用的方法
$ test.pl --library lib/stdlib --library lib/extlib

3. 对键值对的参数传递
有时我们需要传送一些键值对到程序中进行处理,就需要使用到这个功能了.
GetOptions ("define=s" => \%defines);
GetOptions ("define=s%" => \$defines);

使用的方法
$ test.pl --define os=linux --define vendor=redhat

4. 参数的别名
我们需要参数加个简写之类的别名时,可以使用下面的方法:
GetOptions ('length|height=f' => \$length);

第一个名称为 primary name, 其他的名称为 alias(可有多个alias名称) ,当使用hash参数时, 使用primary name作为key值。

5. 参数的简称及大小写
GetOptions ('length|height=f' => \$length, "head" => \$head);

若没有特别设定, Getopt会忽略参数的大小写, 也就是 -l or -L 指的都是同一个参数(–length)

对于不传递参数的选项,也就是一些开关类型,可以在第一部分后接"!",这表示该选项不接收自变量,但是可以通过在前面加上no变成负的(例如,"more"选项的-nomore)。如果不是用"!",而是"+",这表示它会在每次出现的时候增加一个变量。如果选项出现在命令行里,那么相关的变量被设置为1;如果负的选项出现了,那么相关的变量就被设置为0。

6. hash参数值(有名称及参数值)
GetOptions ("define=s" => \%defines);
or
GetOptions ("define=s%" => \$defines);

示例:
$ test.pl –define os=linux –define vendor=crux



以下内容摘自于:Professional scripts are a snap with Getopt::Long,感谢原作者。

Type checking(类似检查)

Getopt::Long provides basic type checking for strings, integers and floating point numbers. I've already added a string argument for the license holder's name, so I'll add an integer option for the license year:
use Getopt::Long;

GetOptions(
  'holder=s' => \my $holder_name,
  'year=i'   => \my $year,
) or die "Invalid options passed to $0\n";

print "$holder_name $year\n";

Running the program again, it will now accept a --year argument:
./license -h "Love FreeOA" --y 2020
Love FreeOA 2020

Note how I was able to pass -y 2014 and Getopt::Long knew to assign it to $year. Getopt::Long will also do basic type checking, so if a non-integer value is passed, it will print and warning and the script will die.

./license -h "Love FreeOA" --year abcd
Value "abcd" invalid for option year (number expected)
Invalid options passed to ./getopt

I'm going to add an option for the license type, so the user can specify which license text they want such as the GPL, MIT or BSD licenses (there are many more).

use Getopt::Long;

GetOptions(
  'holder=s' => \my $holder_name,
  'year=i'   => \my $year,
  'type=s'   => \my $type,
) or die "Invalid options passed to $0\n";

print "$holder_name $year $type\n";


Boolean options(开关类型选项)

Finally I want to add a boolean option for whether to print out the full license text or not. To use boolean options with Getopt::Long, it's the same as with other options except that you don't specify the type after the option name:
use Getopt::Long;

GetOptions(
  'holder=s' => \my $holder_name,
  'year=i'   => \my $year,
  'type=s'   => \my $type,
  'fulltext' => \my $fulltext,
) or die "Invalid options passed to $0\n";

print "$holder_name $year $type $fulltext\n";

The fulltext option does not take a value and will be initialized as 1 if present, or undef if not:
$ ./license -h "Love FreeOA" -y 2012 -t FreeBSD -fulltext
Love FreeOA 2012 FreeBSD 1


Default values(默认值)

Some options I can give default values to. For example if the user doesn't pass the year they want the license for, I'll assume they want the current year.

use Getopt::Long;
use Time::Piece;

GetOptions(
  'holder=s' => \ my $holder_name,
  'year=i'   => \(my $year = year_now()),
  'type=s'   => \(my $type = 'artistic 2.0'),
  'fulltext' => \ my $fulltext,
) or die "Invalid options passed to $0\n";

sub year_now{
  my $localtime = localtime;
  return $localtime->year;
}

print "$holder_name $year $type $fulltext\n";

I've added the Time::Piece module, which is a useful module for datetime handling, and a subroutine year_now which returns the current year. Meanwhile I've updated GetOptions to assign the current year to the $year variable. This will be overridden if the user passes the year argument. I've also given the license type the default value of "artistic 2.0" as that is the same license as Perl 5 (and the license used by many modules).


Mandatory parameters(强制性的参数)

So far so good, but what about mandatory parameters? This script will not work unless the user passes the license holder information. For mandatory parameters I have to check for their presence myself, Getopt::Long can't help me here. Luckily it's a simple check:

use Getopt::Long;
use Time::Piece;

GetOptions(
  'holder=s' => \ my $holder_name,
  'year=i'   => \(my $year = year_now()),
  'type=s'   => \(my $type = 'artistic 2.0'),
  'fulltext' => \ my $fulltext,
) or die "Invalid options passed to $0\n";

# check we got a license holder
die "$0 requires the license holder argument (--holder)\n" unless $holder_name;

sub year_now{
  my $localtime = localtime;
  return $localtime->year;
}

print "$holder_name $year $type $fulltext\n";

In case you're wondering, the variable $0 is a special variable that is the program's name. It's a handy shortcut for exception messages and cheating at writing quines (like this: open+0;print<0>).


Help text(帮助打印)

We're almost done, but Getopt::Long has more tricks up its sleeve. I'll add some basic documentation to this script, in Pod:
use v5.20;
use Time::Piece;
use Getopt::Long 'HelpMessage';

GetOptions(
  'holder=s' => \ my $holder_name,
  'year=i'   => \(my $year = year_now()),
  'type=s'   => \(my $type = 'artistic 2.0'),
  'fulltext' => \ my $fulltext,
  'help'     =>   sub { HelpMessage(0) },
) or HelpMessage(1);

# die unless we got the mandatory argument
HelpMessage(1) unless $holder_name;

print_license($holder_name, $year, $type, $fulltext);

sub year_now{
  my $localtime = localtime;
  return $localtime->year;
}

# tbc
sub print_license { ... }

=head1 NAME

license - get license texts at the command line!

=head1 SYNOPSIS

  --holder,-h     Holder name (required)
  --year,-y       License year (defaults to current year)
  --type,-t       License type (defaults to Artistic 2.0)
  --fulltext,-f   Print the full license text
  --help,-h       Print this help

=head1 VERSION

0.01

=cut

The documentation is pretty minimal, just the program name, synopsis of its arguments and a version number. I've replaced the print statement with a stub function print_license, which is where the main program would be implemented. I've replaced the die calls with the Getopt::Long function HelpMessage. This will print a usage help text and exit the program when called. Let's try it out:

$ ./license -k
Unknown option: k
Usage:
    --holder, -h    Holder name (required)
    --year, -y      License year (defaults to current year)
    --type, -t      License type (defaults to Artistic 2.0)
    --fulltext, -f  Print the full license text
    --help, -h      Print this help

Not bad! HelpMessage takes an exit value to return to the OS. If the user passes the argument --help the program should print the usage and exit without error (value zero). However if they don't pass any arguments at all or if they pass any invalid arguments, the same usage text will be printed but the program will exit with 1, indicating that something went wrong.



本方参考源:
http://docstore.mik.ua/orelly/perl3/perlnut/ch08_117.htm
http://www.php-oa.com/2009/04/04/perl_getopt-long.html