Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am writing a shell script with a few variables that should be configured by the user. There will be an installer for downloading and configuring the script, possibly by asking a series of question. The script in question is aimed at other developers.

This can be implemented in a number of ways:

  1. Use placeholders in the script itself and use sed to replace them during installation (something like this: http://stackoverflow.com/questions/415677/how-to-replace-placeholders-in-a-text-file)

    • Pros: All variable definitions are contained within the script. It's easy to download the script manually and configure the variables for users who prefer an editor over the installer.

    • Cons: It's hard to reconfigure the variables through the installer once they are in place. Unless I create a more complex regexp which would be prone to errors.

  2. Use a config file, basically another shell script with assignments, and use source to include it. (And probably place it in ~/.scriptname? The main script is copied to /usr/local/bin)

    • Pros: It's easy to reconfigure the script. Could even add a parameter for doing so from the main script (Would probably work in the first solution as well, but editing a script from itself doesn't sound like a very good idea)

    • Cons: The script is now dependent on two files and the user is required to run the installer for the configuration file to be created. This can be solved by auto generating a config file if none exists. But locating an external configuration file will still be more cumbersome for users who just want to download the script, edit it, and be done with it.

Also, a few options regarding how the configuration should be managed by the user after the installation:

  1. Git like
    $ myscript config server.host example.org $ myscript config server.proxypath /home/johndoe/proxy $ myscript config server.httppath /home/johndoe/web

  2. Interactive
    $ myscript config
    Enter the server hostname: example.org
    Enter the path to the proxy on the server: /home/johndoe/proxy
    Enter the path to the http directory on the server: /home/johndoe/web

  3. getopts with long options
    $ myscript --host example.org --proxypath /home/johndoe/proxy --httppath /home/johndoe/web

  4. Simple
    $ myscript config example.org /home/johndoe/proxy /home/johndoe/web

Are there any other ways of doing this that you would consider?
Any best practices, anything elegant?

share|improve this question
2  
I do not doubt that you can write a shell script that does all this, but the question is why you want to write something so complex as it requires an installer in a shell script. Anyway, look at how the Linux kernel configuration system manages its configuration file. –  user1249 Aug 6 '12 at 0:20
    
Well. The 'installer' script would only download the real script, copy it to its right location and ask a series of questions for the configuration (3-4 variables). This way I can give users a single command line, wgetting the install script and pipe it to /bin/sh. Of couse I could skip the installer and just add an 'install' parameter to the main script. Maybe a better solution, what do you think? –  Charlie Rudenstål Aug 6 '12 at 0:27
    
"but the question is why you want to write something so complex", Here's the script in question: github.com/charlie-rudenstal/depo I'm trying to reduce the amount of steps new users are required to perform, especially during the installation. Looking into making the required server setup automatic as well. –  Charlie Rudenstål Aug 6 '12 at 0:35

3 Answers 3

up vote 3 down vote accepted

What would I expect from a sane program (a shell script or not):

  • I never ever have to alter the executable to just configure it. This is not an OS kernel.
  • I can pass any setting using command line. This is a must for every piece of information that does not have a reasonable default. The only exception is a password which needs interactive input.
  • Optionally, I can pass a setting using an environment variable.
  • I can write the settings down into a config file, and this file will be used if it is present under a well-known name, or explicitly pointed to using the two methods above.
  • The config file uses the very same setting names and syntax as command line.
share|improve this answer
    
Great advice. Would this be your prefered order? (1) Check passed settings in command line (2) Check setting in a .scriptnameConfig in the same directory (3) Check setting in an environment variable (4) Check setting in a .scriptnameConfig in ~/.scriptnameConfig (5) Use default setting –  Charlie Rudenstål Aug 7 '12 at 13:43
    
"The config file uses the very same setting names and syntax as command line." - How is this supposed to look? I was going to use the assignment syntax for regular shell scripts: SETTING=VALUE. Wouldn't command like syntax feel a bit strange inside a config file? –  Charlie Rudenstål Aug 7 '12 at 13:46
    
See how mount or ssh allow you to use the same syntax on the command line and in config. You don't need to totally copy the command line syntax; instead of '--foo=bar' you can use 'foo = bar'. If you used 'BarOption: Foo' instead, it would be far less convenient: the need to remember if the case is significant, which keyword is accepted in the file and which on command line, and the inability to copy-paste a working command line into a config file with only cosmetic editing. –  9000 Aug 7 '12 at 16:34

Editing placeholders is error prone.

I would go with using a Config file.

Your concern about dependency is valid, however, I don't remember using too many tools that is composed of a single file. So theoretically you are correct, but practically it should be quite OK.

A third option is to make the configuration software write a new tailored version that is specific to the selected options and parameters. This may be harder to write and test of course :)

share|improve this answer

When I need to write an elaborate script with various configuration options I use Python with the argparse and ConfigParser libraries. Those help with implementation but the process applies to any shell script:

  1. Look for a config file. If one exists, read any settings it has into a dictionary / lookup table.
  2. Parse named command line arguments. For each argument provided, override the value loaded from the config file if it exists. For any argument not passed in the command line and not in the config, use a default.
  3. Execute the script's main function
  4. If the config file doesn't exist, write the passed and/or default values to it.

My preference is for a config file to hold the preferred options when the script is going to be used repeatedly, but let any command line arguments override. Write the config file using those parameters the first time it's run. The config file can then be shared and committed to a code repository.

In my most recent case, I also wrote the defaults to the [DEFAULT] section at the top of the config file, then had a section for each "environment" with appropriate overrides for each. The "environment" is the first unnamed parameter to the script. So in this case parameters are chosen as built-in default -> config file default -> config file section value -> command-line parameter. An additional command line parameter gives the option to overwrite the existing config with the latest run's value. This config file is written into the current directory so it applies per project and can be committed with the rest of the code. Anyone else checking out the same project will then start with the same configuration.

share|improve this answer
    
"An additional command line parameter gives the option to overwrite the existing config with the latest run's value." This is an interesting approach. A handy way to combine parameters with configuration. –  Charlie Rudenstål Aug 7 '12 at 19:32

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.