简体   繁体   中英

Perl: command-line override of config file settings?

I'm building a script that utilizes a config file (YAML) to read in all the necessary configuration information, then prints out all the necessary steps a Linux Admin needs to step through to build a server.

A required option is for the Linux Admin that's running the script to be able to override any of the item/value pairs from the config file, at the command-line.

The way I'm currently handling this seems overly cumbersome and I know there's got to be a more innovative and less clunky way to do this.


In the code I:

  1. Parse the YAML config file with YAML::Tiny

     location: continent: na country: us city: rh 
  2. Create variables with the same names as the config file items, assigning the values from the config file.

     my $yaml = YAML::Tiny->new; $yaml = YAML::Tiny->read($config_yml); my $continent = $yaml->[0]->{location}->{continent}; my $country = $yaml->[0]->{location}->{country}; my $city = $yaml->[0]->{location}->{city}; 
  3. Use Getopt::Long and assign the variables, overriding anything passed at the command-line.

     GetOptions ( "city=s" => \\$city, "continent=s" => \\$continent, "country=s" => \\$country, ); 

So those are just 3 item/values pairs, my actual config has over 40 and will change...Which makes for a bit of work to have to keep updating. Any suggestions?

You can let the admin override the YAML settings with a single, flexible switch similar to what ssh(1) does with -o . This is especially appropriate if the config settings are numerous and likely to change.

$ myscript -o location:city=rh --option location:country=us

Now, inside the script, you might keep all your runtime config bundled together in a hash for convenience (rather than having $this_and_that_opt scalars proliferate over time). Option parsing would then look something like this:

# First, set up %GlobalAppCfg from defaults and YAML
# now handle "-o location:country=us"
GetOptions('option|o=s' => sub {
                              my (undef, $optstring) = @_;

                              my ($userkey, $val) = split('=', $optstring, 2);
                              my ($major, $minor) = split(':', $userkey,   2);

                              $GlobalAppCfg->{$major}->{$minor} = $val;
                            },
            ...);

or whatever. You can normalize config keys and values, handle arbitrarily deep key/subkey/subkey configs, etc. This can get slippery, so you might like to key-lock that global hash.

看一下与GetOpt和YAML结合的一些Config模块,可能是Config :: YAMLConfig :: YAML :: Tiny

Just a sketch, but

  1. In your GetOptions call, could you use "deep references" into the YAML structure, thereby getting rid of the "intermediate" variables?

  2. By looking at the generated YAML structure, could you not generate the GetOptions call automatically (based on what variables you actually see in the YAML). By generate, I mean, create the call as a string, and then use "eval" to actually execute it.

  3. If you want the "intermediate variables" for convenience, you could probably generate those yourself from the YAML structure, also as a string, and then use "eval" to actually create the variables.

As I said, just a sketch.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM