home | tags


configuration files for shell scripts

tags: #cli #expert #neat-trick

problem and common solutions

Many programs use a configuration file to store various settings and options. Common formats for these files are JSON, YAML, TOML, and the Windows “INI” format. While many programming languages have libraries to handle JSON etc., bash doesn’t seem to, or at least nothing simple enough; you often need special code as well as external tools to parse the file.

Also, none of them trivially/easily allow you to update values programmatically (if they do at all).

For shell, a common technique is to make the config file actually be a valid shell script that contains only VARIABLE="value" assignments, and have the main script source it. This has some downsides: it is not whitespace tolerant, to start with, which makes it hard for non-programmers to update the config file. More importantly, a lot of people don’t like the fact that every line in the sourced file is effectively going to be executed – it’s code not data.

git-config as a “database”

Here’s a neat little trick: use git config. Git’s config file syntax is simple, easy to understand, and easy to edit. An added bonus is that the git config command makes it trivial to not only read those values but even set them if required.

And yes it is an external command, but everyone already has git anyway right? :)

(The only thing to keep in mind is that you should probably not use it inside a tight inner loop of your shell script!)

example

Here’s a simple example, from one of my former team members. Note especially the simplicity of the getconf and setconf functions, and their use in the main body of the script.

First, here’s the “database”:

$ cat myconf
[display]
        height = 40
        width = 80
[filter]
        pre = gzip -d
        post = zstd

Then the code to read and write it:

#!/bin/bash

getconf() { git config --file=myconf --get "$@"; }
setconf() { git config --file=myconf "$@"; }

H=`getconf display.height`
W=`getconf display.width`
echo H=$H, W=$W.

setconf display.width 128
echo "width set to 128"

And finally this is what it looks like when executed. Notice that the display width value has changed!

$ ./mypgm
H=40, W=80.
width set to 128
$ cat myconf
[display]
        height = 40
        width = 128
[filter]
        pre = gzip -d
        post = zstd