Sprad has asked for the wisdom of the Perl Monks concerning the following question:

I have a script that reads data from a configuration file. I'd like to remove all hard-coding from the script and put anything that might need to be changed into the config file. Unfortunately, the one bit of data I can't figure out how to move is... the path to the config file. It won't necessarily be in the same directory as the script. And I'd rather not require that as a parameter to the script. Is there a way around this one?

A fair fight is a sign of poor planning.

Replies are listed 'Best First'.
Re: Avoiding hard-coding
by Abigail-II (Bishop) on Nov 15, 2003 at 00:17 UTC
    This is a known problem, and solved by a gazillion of applications. It usually goes, in precedence order:
    • Command line argument(s)
    • Environment variables.
    • Set of fixed locations to search (files and/or directories).


Re: Avoiding hard-coding
by hossman (Prior) on Nov 14, 2003 at 23:47 UTC

    You might be interested in Config::Find or Config::Auto ... they were both built to support the idea that for theapplication named "foo" there are a fairly common set of places to look for "foo" configuration files. -- unless of course the user tells me exactly which file to use, in which case i'll trust them.

Re: Avoiding hard-coding
by liz (Monsignor) on Nov 14, 2003 at 23:19 UTC
    Hmmm... other than having the file at a standard location (as is the case with e.g. /etc/passwd), or using an environment variable, the only thing I can then think of is the PSI::ReadMindOfUser module.


      That would indeed be a very handy module to have lying around. Heck, it could even write the script for you in the first place...
Re: Avoiding hard-coding
by QM (Parson) on Nov 14, 2003 at 23:29 UTC
    You could change the problem around so that the config file is really a script, and calls the script (with the path to the config file as a parameter). The script reads the config file, and all of your hard coding is in one place.

    This also allows multiple config files to share a script, but behave differently.

    Quantum Mechanics: The dreams stuff is made of

Re: Avoiding hard-coding
by mirod (Canon) on Nov 14, 2003 at 23:38 UTC

    I use a default location (using FindBin if the default location is the code directory) and a command line argument to change it if needed:

    use YAML qw(LoadFile); # my config files are often in YAML use FindBin qw($Bin); # $Bin gives the code directory use Getopt::Std; # Getopt::Long is probably better my %opt; getopts( 'c:' => \%opt); # -c <config_file> $opt{c} ||= "$Bin/config.yaml"; # default location # this is far from perfect, I should really open the file properly, # slurp it and then use YAML to parse the content # as it is, if the file exists but cannot be opened the # error message is a bit ugly... die "cannot find file config file $opt{c}" unless( -f $opt{c}); my $env= LoadFile( $opt{c});
Re: Avoiding hard-coding
by pg (Canon) on Nov 14, 2003 at 23:23 UTC

    Use environment variable. Environment variables are stored in %ENV.

Re: Avoiding hard-coding
by coreolyn (Parson) on Nov 17, 2003 at 13:12 UTC

    I find that if my app grows I invariably end up doing the following. (Ususally I need my stuff to run in Win32 and Solaris)

    • Kick off the perl script with a bat script with the same name as a shell script and available via normal system paths. ( That way both have the same command line)
    • Use the bat/shell script to set local library locations and cd to the root of the application/scripts
    • (After my command line parsing) a begin block to get my libraries to load the way I want/need them to
    • Pull in a config file that utilizes relative directories to load into the environment (%ENV).

    While this isn't optimal, it is reliable and reuaable, and has become so much a pattern I just start with this style from a template (which includss generic POD and of course strict & -w )

    Unfortunately the company has laid ownership to the template, but it is easy enough to roll your own