Perl:命令行参数的处理

相关阅读

Perl:正则表达式

Perl:什么是其特有的autovivafacation性质?

Perl:匿名数组嵌套的解引用相关问题


        命令行参数是shell和perl交互的一个重要媒介,本文介绍了如何在Perl中对命令行参数进行处理。

        首先我们给出所有的源程序,再分别对其中的各个子例程进行讲解。

sub print_and_exit {
  print @_, "\n";
  exit 1;
} # print_and_exit

sub 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_argv

sub 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_type


sub 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_type

sub 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_default


sub combine_scalar {
  my ($hr, $hv) = @_;

  for my $opt ( keys %$hv ) {
    if ( ${$hr->{$opt}}{'perl_type'} eq 'scalar') {
      $hv->{$opt} = $hv->{$opt}->[0];
    }
  }

} # combine_scalar

sub 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_argv


sub print_argv {
  my ($hv) = @_;
  for my $opt ( keys %$hv ) {
    print "$opt =>";
    for my $pv ( @{ $hv->{$opt} } ) {
      print " $pv";
    }
    print "\n";
  }
} # print_argv

my %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设计实践》

你可能感兴趣的:(Perl,perl,开发语言,脚本语言,命令行处理)