Pregunta

Tengo un script en Perl que establece las variables en la parte superior de los directorios y archivos que se van a utilizar. También requiere unas pocas variables que se establezcan como argumentos de línea de comandos. Ejemplo:

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

Esto funciona bien en mis entornos dev, prueba y producción. Sin embargo, yo estaba tratando de hacer que sea más fácil para anular ciertas variables (sin entrar en el depurador) para desarrollo y pruebas. (Por ejemplo, si quiero poner mi archivo_entrada = "/tmp/my_input_file.dat"). Mi idea era utilizar la función getOptions para manejar esto, algo como esto:

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, sólo pueden usarse una vez (por lo que yo sé). Se requieren los 4 primeros argumentos en mi primer snippit, el último 7 directamente encima son opcionales. Creo que la situación ideal sería configurar los valores por defecto como en mi primera snippit código, y entonces de alguna manera tienen prioridad sobre cualquiera de ellos que se han establecido si se pasan argumentos en la línea de comandos. Pensé en el almacenamiento de todas mis opciones en un hash y luego usar ese hash de la hora de configurar cada variable con el valor por defecto a menos que exista una entrada en el hash, pero que parece que añadir una gran cantidad de lógica adicional. ¿Hay una manera de llamar getOptions en dos lugares diferentes en el guión?

No estoy seguro si eso tiene algún sentido.

Gracias!

¿Fue útil?

Solución

Aquí hay otro enfoque. Utiliza matrices de nombres y un hash para almacenar las opciones. Esto hace que todas las opciones verdaderamente opcional, pero valida los requeridos a menos que incluyen "--debug" en la línea de comandos. Independientemente de si se utiliza "--debug", puede sustituir cualquiera de los otros.

Se podría hacer controles lógicos más explícitos si eso es importante para usted, por supuesto. Incluí "--debug" como un ejemplo de cómo omitir las opciones básicas como "punto_de_montaje" si sólo vamos a anular el Output_file variables "" "archivo_entrada" y de todos modos.

La idea principal aquí es que al mantener conjuntos de nombres de opciones en las matrices, puede incluir controles lógicos contra los grupos con relativamente poco código.

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

Otros consejos

Parece que usted necesita cambiar su programa para utilizar los archivos de configuración en lugar de la configuración no modificable. He dedicado un capítulo entero de Mastering Perl para esto. Usted no quiere cambiar el código fuente para probar el programa.

Hay muchos módulos Perl en CPAN que hacer que los archivos de configuración de una característica fácil de añadir. Elija el que mejor se adapte a sus datos de entrada.

Una vez que obtenga un mejor modelo de configuración en su lugar, se puede configurar fácilmente los valores por defecto, tomar valores desde múltiples lugares (archivos, de línea de comandos, etc.), y fácilmente probar el programa con diferentes valores.

Creo que lo que me gustaría hacer es establecer input_directory et al a "undef", y luego ponerlos en los getopts, y luego después, probar si siguen undef y si es así asignarlos como se muestra. Si los usuarios son técnicamente sofisticado suficiente para entender "si me dan una ruta relativa es relativa a $mount_point/$sub_dir", entonces me gustaría hacer análisis adicionales en busca de un primer "/".

getOptions pueden ser llamados con una matriz como sus datos de entrada. Lea la documentación .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top