我有一个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只能调用一次(据我所知)。我的第一个snippit中的前4个参数是必需的,上面的最后7个参数是可选的。我认为一个理想的情况是在我的第一个代码snippit中设置默认值,然后以某种方式覆盖在命令行传递参数时已设置的任何默认值。我考虑将所有选项存储在哈希中,然后在使用默认值设置每个变量时使用该哈希,除非哈希中存在条目,但这似乎增加了许多额外的逻辑。有没有办法在脚本中的两个不同位置调用GetOptions?
不确定这是否有意义。
谢谢!
答案 0 :(得分:7)
听起来您需要更改程序以使用配置文件而不是硬编码配置。我将Mastering Perl的整个章节用于此。您不想更改源代码来测试程序。
CPAN上有许多Perl模块,它们使配置文件成为一个易于添加的功能。选择最适合输入数据的那个。
一旦您获得了更好的配置模型,您可以轻松设置默认值,从多个位置(文件,命令行等)获取值,并使用不同的值轻松测试程序。
答案 1 :(得分:6)
这是另一种方法。它使用名称数组和哈希来存储选项。它使所有选项都是可选的,但验证了所需的选项,除非在命令行中包含“--debug”。无论您使用“--debug”,都可以覆盖其他任何一个。
当然,如果这对你很重要,你可以做更明确的逻辑检查。我包括“--debug”作为如何省略像“mount_point”这样的基本选项的例子,如果你只是要覆盖“input_file”和“output_file”变量。
这里的主要思想是通过在数组中保留选项名称集,您可以使用相对较少的代码对组进行逻辑检查。
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
答案 2 :(得分:3)
我认为我要做的是将input_directory
等设置为“undef”,然后将它们放入getopts中,然后测试它们是否仍然是undef,如果是,则如图所示分配它们。如果您的用户在技术上足够精通以理解“如果我给出相对于$mount_point/$sub_dir
的相对路径”,那么我会进行额外的解析,寻找初始的“/".
答案 3 :(得分:0)
可以使用数组作为输入数据调用GetOptions。阅读documentation。