13

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: https://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?

3
  • 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, 2012 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? Aug 6, 2012 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. Aug 6, 2012 at 0:35

3 Answers 3

7

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.
3
  • 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 Aug 7, 2012 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? Aug 7, 2012 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, 2012 at 16:34
3

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.

2
  • "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. Aug 7, 2012 at 19:32
  • +1, also I would recommend setting defaults in a default.config file located in the same directory as the script, then looking for a config file at ~/.scriptname to override these values. That way every value has a valid default value and its easier to maintain.
    – Aaron
    Aug 16, 2018 at 12:32
2

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 :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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