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 は 1 回しか呼び出せません (私の知る限り)。最初のスニピットの最初の 4 つの引数は必須で、すぐ上の最後の 7 つの引数はオプションです。理想的な状況は、最初のコード スニピットのようにデフォルトを設定し、コマンド ラインで引数が渡された場合に設定された設定を何らかの方法で上書きすることだと思います。すべてのオプションをハッシュに保存し、ハッシュにエントリが存在しない限り、各変数をデフォルト値で設定するときにそのハッシュを使用することを考えましたが、それは多くの追加ロジックを追加するようです. スクリプトの 2 つの異なる場所で GetOptions を呼び出す方法はありますか?

それが意味をなすかどうかはわかりません。

ありがとう!

4

4 に答える 4

7

ハードコードされた構成ではなく、構成ファイルを使用するようにプログラムを変更する必要があるようです。私はPerlのマスターの章全体をこれに捧げました。プログラムをテストするためにソースコードを変更したくない。

CPANには、構成ファイルを簡単に追加できる機能にする多くのPerlモジュールがあります。入力データに最適なものを選択してください。

より適切な構成モデルを導入したら、デフォルト値を簡単に設定し、複数の場所(ファイル、コマンドラインなど)から値を取得し、さまざまな値でプログラムを簡単にテストできます。

于 2008-12-10T15:23:01.807 に答える
6

ここに別のアプローチがあります。名前の配列とハッシュを使用してオプションを格納します。これにより、すべてのオプションが完全にオプションになりますが、コマンド ラインに「--debug」を含めない限り、必要なものは検証されます。「--debug」を使用するかどうかに関係なく、他のものをオーバーライドできます。

もちろん、それが重要な場合は、より明示的なロジック チェックを行うこともできます。「input_file」変数と「output_file」変数をオーバーライドするだけの場合に、「mount_point」などの基本的なオプションを省略する方法の例として、「--debug」を含めました。

ここでの主なアイデアは、オプション名のセットを配列に保持することで、比較的少ないコードでグループに対するロジック チェックを含めることができるということです。

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 に答える