tags: #cli #expert #neat-trick
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.
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!)
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 = zstdThen 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