相关阅读
Perl:正则表达式
Perl:什么是其特有的autovivafacation性质?
Perl:匿名数组嵌套的解引用相关问题
命令行参数是shell和perl交互的一个重要媒介,本文介绍了如何在Perl中对命令行参数进行处理。
首先我们给出所有的源程序,再分别对其中的各个子例程进行讲解。
sub print_and_exit {print @_, "\n";exit 1;
} # print_and_exitsub read_argv {my ($aref, $hv) = @_;my ($opt);for my $arg ( @$aref ) {if ( $arg =~ /^-/ ) {$opt = $arg;if ( exists $hv->{$opt} ) {print_and_exit( "Repeated option: $arg" );}else {@{ $hv->{$opt} } = ();}}elsif ( defined $opt ) {$arg =~ s/^\s*// ;push @{ $hv->{$opt} }, $arg;}else {print_and_exit( "Un-support option: $arg" );}}
} # read_argvsub check_argv_perl_type {my ($hr, $hv) = @_;for my $opt ( keys %$hv ) {if ( exists $hr->{$opt} ) {if ( ${$hr->{$opt}}{'perl_type'} eq 'scalar') {if ( @{ $hv->{$opt} } != 1 ) {print_and_exit( "Error: only one parameter is expected to '$opt'" );} }elsif ( ${$hr->{$opt}}{'perl_type'} eq 'array') {if ( @{ $hv->{$opt} } < 1 ) {print_and_exit( "Error: one or more parameter is expected to '$opt'" );}}else {print_and_exit( "Error: unknown 'perl_type' of '$opt'" );}}else {print_and_exit( "Un-support option: '$opt'" );}}
} # check_argv_perl_typesub check_argv_data_type {my ($hr, $hv) = @_;for my $opt ( keys %$hv ) {if ( exists $hr->{$opt} ) {next unless exists $hr->{$opt}{'data_type'};if ( $hr->{$opt}{'data_type'} eq 'inputfile') {for my $arg ( @{ $hv->{$opt} } ) {if ( ! ( (-f $arg) and (-s $arg) ) ) {print_and_exit( "Error: input file is expected to '$opt': $arg" );}}}elsif ( $hr->{$opt}{'data_type'} eq 'num') {for my $arg ( @{ $hv->{$opt} } ) {unless ( ( $arg =~ /^-?\d+$/ )or ( $arg =~ /^-?\d+\.\d+$/ )or ( $arg =~ /^-?\d+[eE]-?\d+$/ )or ( $arg =~ /^-?\d+\.\d+[eE]-?\d+$/ )) {print_and_exit( "Error: number is expected to '$opt': $arg" );}}}elsif ( $hr->{$opt}{'data_type'} eq 'inputdir') {for my $arg ( @{ $hv->{$opt} } ) {if ( ! -d $arg ) {print_and_exit( "Error: directory is expected to '$opt': $arg" );}}}}else {print_and_exit( "Un-support option: '$opt'" );}}
} # check_argv_data_typesub get_default {my ($hr, $hv) = @_;for my $opt ( keys %$hr ) {next if exists $hv->{$opt} ;if ( exists $hr->{$opt}{'default'} ) {### 'default' => "some_scalar", OR 'default' => ["some", "element", "of", "array"],$hv->{$opt} = $hr->{$opt}{'default'}; }else {print_and_exit( "Error: no input or default for '$opt'" );}}} # get_defaultsub combine_scalar {my ($hr, $hv) = @_;for my $opt ( keys %$hv ) {if ( ${$hr->{$opt}}{'perl_type'} eq 'scalar') {$hv->{$opt} = $hv->{$opt}->[0];}}} # combine_scalarsub Handle_argv {my ($aref, $hr, $hv) = @_;read_argv($aref, $hv);check_argv_perl_type($hr, $hv);check_argv_data_type($hr, $hv);get_default($hr, $hv);combine_scalar($hr, $hv);
} # Handle_argvsub print_argv {my ($hv) = @_;for my $opt ( keys %$hv ) {print "$opt =>";for my $pv ( @{ $hv->{$opt} } ) {print " $pv";}print "\n";}
} # print_argvmy %rule_of_opt = ('-s' => {'perl_type' => 'scalar','data_type' => 'inputfile',},'-a' => {'perl_type' => 'array','data_type' => 'num','default' => '5'}
);
my (%value_of_opt) ;
Handle_argv( \@ARGV, \%rule_of_opt, \%value_of_opt );
print_argv( \%value_of_opt );exit 0;
1、print_and_exit
该子例程用于根据参数打印信息并使用exit退出程序。
2、read_argv
该子例程用于将命令行参数读进参数散列中。参数散列的键为命令行参数中各个选项,如"-s"和"-a",值为命令行参数中跟在该选项后的参数,在这里,规定属于一个选项的参数是该选项后至下一个选项间的参数,且选项不能重复,否则会报错"Repeated option",因为属于一个选项的参数可能有多个,需要用数组保存,所以使用$hv->{$opt}保存了一个指向数组的引用(注意,Perl中数组的值和散列的值必须是标量(scalar))。使用push将选项的参数值加入该选项对应值(数组引用)指向的数组中。
3、check_argv_perl_type
该子例程用于检查read_argv所读取的散列中,每个选项的参数数量是否符合散列%rule_of_opt所定义的规则,在代码中,"-s"选项的"perl_type"属性为标量,而"-a"选项的"perl_type"属性为数组。如果不符合,则程序会报错提示参数数量有问题,并退出。
4、check_argv_data_type
该子例程用于检查read_argv所读取的散列中,每个选项的参数类型是否符合散列%rule_of_opt所定义的规则,在代码中,"-s"选项的"data_type"属性为输入文件,而"-a"选项的"perl_type"属性为数字。如果不符合,则程序会报错提示参数类型有问题,并退出。代码中使用了正则表达式对数字进行识别,使用文件操作符-f和-d分别对文件和目录进行识别(有关Perl中正则表达式的内容,可以看Perl:正则表达式)。
5、get_default
该子例程用于在未指定选项时,为其创建默认参数值,默认值可以根据规则是标量或数组,如果一个选项没有出现,且没有默认值,则会报错。
6、combine_scalar
该子例程用于对只有一个参数的选项进行优化,会直接使用$hv->{$opt}保存该参数值,而不是保存指向数组的引用。
7、Handle_argv
这是将子例程整合封装的例程,注意各子例程的调用顺序。
8、print_argv
该子例程可以打印经过处理后的选项参数散列,用于观察结果。
源代码来源于《Pelr语言IC设计实践》