如何将强制和可选命令行参数传递给 perl 脚本?

Posted

技术标签:

【中文标题】如何将强制和可选命令行参数传递给 perl 脚本?【英文标题】:How to pass both mandatory and optional command line arguments to perl script? 【发布时间】:2016-09-24 00:29:37 【问题描述】:

我正在使用 Getopt::Long 将选项传递给我的 Perl 脚本。

但我想做这样的事情:

perl myScript mandatoryArgument1 -optionalArgument1=someValue

如果缺少mandatoryArgument1,我希望脚本抛出错误。如何做到这一点?

【问题讨论】:

您可能会发现this article 很有用。 【参考方案1】:

我对@9​​87654321@ 的处理方式:

sub help  print "Some help"; exit 

sub main 
    GetOptions(
        'file|f=s'   => \( my $file = undef ),
        'tag|t=s'    => \( my $tag = undef ),
        'help|h'     => \( my $printHelp = undef ),
    );

    help() if $printHelp;
    help() unless $file;

[...]


在这种情况下,--file-f 选项是强制性的。我检查是否定义了$file,否则我会中止执行打印程序的帮助。

我不会将--param=*value* 形式的命名 输入参数与无命名参数混合。 也就是说,您可以在调用 Getopt::Long 之前操作 @ARGV 并将其配置为执行您所要求的操作,但是为脚本的用户混合两种类型的输入参数 philosophy 会造成混淆。

#!/usr/bin/env perl
use strict;
use warnings;
use feature qwsay;
use Carp;
use Getopt::Long;    

sub main     
    my $firstParam = shift @ARGV;
    croak "Mandatory parameter not given"
        if (!$firstParam || $firstParam =~ /^-/);

    GetOptions(
        'file|f=s'   => \( my $file = undef ),
        'tag|t=s'    => \( my $tag = undef ),
    );


    say 'Mandatory: ', $firstParam;
    say 'Optional $file: ', $file if $file;
    say 'Optional $tag: ', $tag if $tag;


main();

你可以叫它./test.pl mandatory -f file -t tag

Mandatory: mandatory                                                                                        
Optional $file: file                                                                                      
Optional $tag: tag  

您必须将强制参数限制在固定位置(在我的示例中,问题中的第一个,但也可能是最后一个)。

【讨论】:

【参考方案2】:

好的Getopt::Long 没有这样的机制。它专门processes options

但是,当它完成它的工作时,它会从@ARGV 中删除这些选项,因此一旦完成,您就可以检查预期的参数是否存在。请参阅第二部分,但我想首先建议另一种方法:命名这些参数,然后 Getopt 将处理它们。

然后很容易检查它们是否已提交。例如

use warnings;
use strict;
use feature 'say';
use Getopt::Long;

my $mandatoryArg;
my $opt;

# Read command-line arguments, exit with usage message in case of error
GetOptions( 'name=s' => \$mandatoryArg, 'flag' => \$opt )
    or usage(); 

if (not defined $mandatoryArg) 
    say STDERR "Argument 'name' is mandatory";
    usage();


# The program goes now. Value for $opt may or may have not been supplied

sub usage 
    say STDERR "Usage: $0 ...";   # full usage message
    exit;

所以如果--name string 没有在命令行中给出,$mandatoryArg 保持未定义并且程序退出。该变量不需要默认值,因为它是强制性的,而且它不应该有一个默认值来进行此检查。

参数检查和处理通常更复杂,这就是Getopt 大放异彩的时候。


问题中的mandatoryArgument1 没有提供名称。虽然可以将Getopt 设为act on a non-option input,但它无法检测到预期的不在那里。

该模块允许在命令行的任何位置混合参数和命名选项。请参阅文档中的 Option with other arguments。所以你可以调用程序

script.pl --opt1 value1 unnamed_arg --opt2 value2

但我建议用户在命名选项之后提供它们。

然后,在GetOptions 完成工作后,@ARGV 将包含字符串unnamed_arg,您可以得到它(或发现它不存在)。 GetOptions对命名选项的处理同上。

my ($var1, $var2, $flag);

GetOptions('opt1=s' => \$var1, 'opt2=i' => \$var2, 'f' => \$flag)
    or usage(); 

# All supplied named options have been collected, all else left in @ARGV
# Read the remaining argument(s) from @ARGV, or exit with message

# This can get far more complicated if more than one is expected
my $mandatoryArg1 = shift @ARGV || do 
    say STDERR "Mandatory argument (description) is missing";
    usage();
;

一旦Getopt 拾取命名参数,您必须手动处理@ARGV

如果有多个这样的参数,用户必须严格遵守他们在命令行上的预期相对位置,因为程序通常无法分辨出什么是什么。因此,用户在命令行上混淆了他们的顺序的错误通常不会被捕获。

这会成为一个障碍,我建议最多有一个种未命名的参数,并且仅在必须是什么很明显的情况下,例如文件名)。

虽然所有这些都是可能的,但像 Getopt 这样的模块精确地存在,因此我们不必这样做。


使用'<>'的“名称”为看起来不像选项的输入设置操作

Getoptions( 'opt=s' => \$var, ..., '<>' => \&arg_cb );

sub arg_cb  say "Doesn't look like an option: $_[0]" 

arg_cb 仅在看到非选项参数时才被调用

【讨论】:

以上是关于如何将强制和可选命令行参数传递给 perl 脚本?的主要内容,如果未能解决你的问题,请参考以下文章

Perl 如何将数组作为参数传递给另一个 Perl 脚本

在 Eclipse(Pydev) 中将命令行参数传递给 Python 脚本

如何将命令行参数传递给 spark-shell scala 脚本?

强制将单个参数传递给多可选参数函数

如何将命令行参数传递给 PowerShell ps1 文件

将命令行参数传递给python脚本[重复]