2008-12-10 50 views
-1

我有一個Perl腳本,它爲將要使用的目錄和文件設置頂端附近的變量。它還需要將一些變量設置爲命令行參數。 例子:如何覆蓋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?

不知道這是否有道理。

謝謝!

回答

6

這是另一種方法。它使用名稱和散列數組來存儲選項。它使所有選項真正可選,但驗證所需的選項,除非在命令行中包含「--debug」。無論您使用「--debug」,您都可以覆蓋其他任何人。

當然,如果這對你很重要,你可以做更多的顯式邏輯檢查。如果您只是要重寫「input_file」和「output_file」變量,我將「--debug」作爲如何省略「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 
+0

我喜歡這個 - 你能解釋一下像我的$ var || =「somevalue」這樣的行嗎? $ var如何從命令行獲取選項?還是有一個步驟丟失,它從哈希%opts中拉出來? – BrianH 2008-12-10 16:24:26

0

可以使用數組作爲輸入數據調用GetOptions。閱讀documentation

3

我想我會做的是將input_directory等設置爲「undef」,然後將它們放在getopts中,然後測試它們是否仍然undef,如果是這樣,則如圖所示分配它們。如果你的用戶在技術上足夠複雜以理解「如果我給出一個相對路徑,它是相對於$mount_point/$sub_dir」,那麼我會做額外的解析來尋找一個最初的「/」。

7

這聽起來像你需要改變你的程序使用配置文件,而不是硬編碼的配置。我專門爲此編寫了一整章Mastering Perl。您不想更改源代碼來測試該程序。

CPAN上有許多Perl模塊,使配置文件成爲一個簡單的功能。選擇最適合您的輸入數據的那個。

一旦您獲得了更好的配置模型,您可以輕鬆設置默認值,從多個位置(文件,命令行等)獲取值,並輕鬆測試具有不同值的程序。