1

我有一个 Perl 脚本,它在顶部附近为它将使用的目录和文件设置变量。它还需要将一些变量设置为命令行参数。例子:

use Getopt::Long;

my ($mount_point, $sub_dir, $database_name, $database_schema);
# Populate variables from the command line:
GetOptions(
    'mount_point=s'       => \$mount_point,
    'sub_dir=s'           => \$sub_dir,
    'database_name=s'     => \$database_name,
    'database_schema=s'   => \$database_schema
);
# ...  validation of required arguments here

################################################################################
# Directory variables
################################################################################
my $input_directory    = "/${mount_point}/${sub_dir}/input";
my $output_directory   = "/${mount_point}/${sub_dir}/output";
my $log_directory      = "/${mount_point}/${sub_dir}/log";
my $database_directory = "/db/${database_name}";
my $database_scripts   = "${database_directory}/scripts";

################################################################################
# File variables
################################################################################
my $input_file       = "${input_dir}/input_file.dat";
my $output_file      = "${output_dir}/output_file.dat";
# ... etc

这在我的开发、测试和生产环境中运行良好。但是,我试图让覆盖某些变量(无需进入调试器)更容易进行开发和测试。(例如,如果我想设置我的 input_file = "/tmp/my_input_file.dat")。我的想法是使用 GetOptions 函数来处理这个问题,如下所示:

GetOptions(
    'input_directory=s'      => \$input_directory,
    'output_directory=s'     => \$output_directory,
    'database_directory=s'   => \$database_directory,
    'log_directory=s'        => \$log_directory,
    'database_scripts=s'     => \$database_scripts,
    'input_file=s'           => \$input_file,
    'output_file=s'          => \$output_file
);

GetOptions 只能调用一次(据我所知)。我的第一个片段中的前 4 个参数是必需的,上面的最后 7 个是可选的。我认为理想的情况是在我的第一个代码片段中设置默认值,然后以某种方式覆盖在命令行中传递参数时已设置的任何默认值。我考虑过将所有选项存储在哈希中,然后在使用默认值设置每个变量时使用该哈希,除非哈希中存在条目,但这似乎增加了很多额外的逻辑。有没有办法在脚本的两个不同位置调用 GetOptions?

不确定这是否有意义。

谢谢!

4

4 回答 4

7

听起来您需要更改程序以使用配置文件而不是硬编码配置。我在Mastering Perl中用了整整一章来讨论这个问题。您不想更改源代码来测试程序。

CPAN 上有许多 Perl 模块,它们使配置文件成为易于添加的功能。选择最适合您的输入数据的一种。

一旦获得了更好的配置模型,您就可以轻松地设置默认值,从多个位置(文件、命令行等)获取值,并轻松地使用不同的值测试程序。

于 2008-12-10T15:23:01.807 回答
6

这是另一种方法。它使用名称数组和散列来存储选项。它使所有选项真正成为可选的,但会验证所需的选项,除非您在命令行中包含“--debug”。无论您是否使用“--debug”,您都可以覆盖其他任何一个。

当然,如果这对您很重要,您可以进行更明确的逻辑检查。我将“--debug”作为一个示例,说明如果您要覆盖“input_file”和“output_file”变量,如何省略“mount_point”等基本选项。

这里的主要思想是,通过将选项名称集保存在数组中,您可以使用相对较少的代码对组进行逻辑检查。

use Getopt::Long;

my @required_opts = qw(
    mount_point
    sub_dir
    database_name
    database_schema
);

my @internal_opts = qw(
    input_directory
    output_directory
    log_directory
    database_directory
    database_scripts
    input_file
    output_file
);

my @opt_spec = ("debug", map { "$_:s" } @required_opts, @internal_opts);

# Populate variables from the command line:
GetOptions( \(my %opts), @opt_spec );

# check required options unless 
my @errors = grep { ! exists $opts{$_} } @required_options;
if ( @errors && ! $opts{debug} ) {
    die "$0: missing required option(s): @errors\n";
}

################################################################################
# Directory variables
###############################################################################
my $opts{input_directory}    ||= "/$opts{mount_point}/$opts{sub_dir}/input";
my $opts{output_directory}   ||= "/$opts{mount_point}/$opts{sub_dir}/output";
my $opts{log_directory}      ||= "/$opts{mount_point}/$opts{sub_dir}/log";
my $opts{database_directory} ||= "/db/$opts{database_name}";
my $opts{database_scripts}   ||= "$opts{database_directory}/scripts";

################################################################################
# File variables
################################################################################
my $opts{input_file}    ||= "$opts{input_directory}/input_file.dat";
my $opts{output_file}   ||= "$opts{output_directory}/output_file.dat";
# ... etc
于 2008-12-10T16:05:04.093 回答
3

我想我要做的是将input_directoryet al 设置为“undef”,然后将它们放入 getopts 中,然后测试它们是否仍然是 undef,如果是,则如图所示分配它们。如果您的用户在技术上足够成熟,可以理解“如果我给出一个相对路径是相对于$mount_point/$sub_dir”,那么我会进行额外的解析以寻找初始的“/”。

于 2008-12-10T15:20:37.020 回答
0

可以使用数组作为其输入数据调用 GetOptions。阅读文档

于 2008-12-10T15:12:59.360 回答