Domanda

Ho uno script Perl che imposta le variabili vicino alla parte superiore per le directory ei file che si userà. Richiede anche alcune variabili da impostare come argomenti della riga di comando. Esempio:

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

Questo funziona bene nei miei ambienti dev, test e produzione. Comunque, stavo cercando di rendere più facile per sovrascrivere alcune variabili (senza entrare nel debugger) per lo sviluppo e la sperimentazione. (Per esempio, se voglio impostare la mia file_input = "/tmp/my_input_file.dat"). Il mio pensiero è stato quello di utilizzare la funzione GetOptions per gestire questo, qualcosa di simile:

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 può essere chiamato solo una volta (per quanto ne so). Le prime 4 argomenti a mia prima snippit sono necessari, l'ultimo 7 direttamente sopra sono opzionali. Penso che una situazione ideale sarebbe quella di impostare i valori di default, come nel mio primo snippit codice, e quindi in qualche modo a ignorare qualcuno di loro che sono state impostate se gli argomenti sono stati passati alla riga di comando. Ho pensato a memorizzare tutte le mie opzioni in un hash e quindi utilizzando tale hash quando si imposta ogni variabile con il valore di default a meno che non esista una voce nel hash, ma che sembra aggiungere un sacco di logica aggiuntiva. C'è un modo per chiamare GetOptions in due posti diversi nello script?

Non sono sicuro se questo ha un senso.

Grazie!

È stato utile?

Soluzione

Ecco un altro approccio. Esso utilizza array di nomi e un hash per memorizzare le opzioni. Rende tutte le opzioni veramente opzionale, ma convalida quelli richiesti a meno che non si include "--debug" sulla riga di comando. Indipendentemente dal fatto che si utilizza "--debug", è possibile ignorare tutti gli altri.

Si potrebbe fare controlli logici più espliciti, se questo è importante per voi, naturalmente. Ho incluso "--debug" come un esempio di come di omettere le opzioni di base come "mount_point", se si sta solo andando a sovrascrivere il "file_input" e variabili "output_file" comunque.

L'idea principale è che tenendo serie di nomi di opzione in array, è possibile includere controlli logici contro i gruppi con relativamente poco codice.

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

Altri suggerimenti

Sembra che tu abbia bisogno di cambiare il vostro programma di utilizzare i file di configurazione, piuttosto che la configurazione hard-coded. Ho dedicato un intero capitolo del Mastering Perl per questo. Se non si desidera modificare il codice sorgente per testare il programma.

Ci sono molti moduli Perl su CPAN che rendere i file di configurazione di una funzione semplice per aggiungere. Scegli quello che funziona meglio per i dati di input.

Una volta che si ottiene un modello migliore configurazione in atto, si può facilmente impostare i valori di default, assumere valori da luoghi multipli (file, della riga di comando, ecc), e facilmente testare il programma con valori diversi.

Credo che quello che vorrei fare è impostare input_directory et al a "undef", e poi metterli in getopts, e poi dopo, testare se sono ancora undef e in caso affermativo assegnano loro come mostrato in figura. Se gli utenti sono tecnicamente sofisticati abbastanza per capire "se io do un percorso relativo è relativo al $mount_point/$sub_dir", quindi farei ulteriore analisi alla ricerca di una prima "/".

GetOptions possono essere chiamati con un array come i dati di input. Leggi la documentazione .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top