How to store configuration within shell script

Store runtime configuration within shell script using simple but an effective method.

Shell script

I will use the following shell script to illustrate the idea. Nothing fancy, it will display available disk space on specific server and partition.

#!/usr/bin/env bash
# Display available disk space on specific server and partition

# default parameters
default_bastion=""
default_busername=""
default_server="localhost"
default_username="milosz"
default_partition="/srv"

# nextcloud server
nextcloud_server="nextcloud.local"
nextcloud_partition="/data"

# dokuwiki server
dokuwiki_bastion="bastion.example.org"
dokuwiki_busername="bouncer"
dokuwiki_server="192.0.2.10"
dokuwiki_username="dokuwiki"
dokuwiki_partition="/wiki"

# kolab server
kolab_bastion="bastion.example.org"
kolab_busername="bouncer"
kolab_server="192.0.2.20"
kolab_username="monitoring"
kolab_partition="/"

# get defined servers/applications
applications="$((set -o posix; set) | awk -F '='  '/_server/ {split($1,array,"_"); print array[1]}' | grep -v default)"

# get defined attributes
attributes="$((set -o posix; set) | awk -F '=' '/default_/ {split($1,array,"_"); print array[2]}')"

for application in $applications; do
  # define attributes for server/application
  for attribute in $attributes; do
    application_attribute="${application}_${attribute}"
    default_attribute="default_${attribute}"
    if [ -n "${!application_attribute}" ]; then
      eval "${attribute}"="${!application_attribute}"
    else
      eval "${attribute}"="${!default_attribute}"
    fi
  done

  # perform an action
  if [ -n "$bastion" ]; then
    bastion_param="-J ${busername}@${bastion}"
  else
    bastion_param=""
  fi
	echo -n "$server: "
  ssh $bastion_param $server -l $username "bash -c 'df -h --output=avail $partition | sed 1d'"
done

Usage

Execute the above-mentioned shell script to see available disk space on specified servers.

nextcloud.local:   87G
192.0.2.10:   98G
192.0.2.20:  5,5G

How it works

Attributes

Define default values, remember to include the empty ones.

# default parameters
default_bastion=""
default_busername=""
default_server="localhost"
default_username="milosz"
default_partition="/srv"

These variables will be used to extract attribute names.

# get defined attributes
attributes="$((set -o posix; set) | awk -F '=' '/default_/ {split($1,array,"_"); print array[2]}')"

Extracted attribute names.

attributes="bastion busername server username partition"

Applications

Define attributes for each application.

# nextcloud server
nextcloud_server="nextcloud.local"
nextcloud_partition="/data"
[...]

These variables will be used to extract application names.

Notice, I am using server attribute as an application indicator in this example.
# get defined servers/applications
applications="$((set -o posix; set) | awk -F '='  '/_server/ {split($1,array,"_"); print array[1]}' | grep -v default)"

Extracted applications names.

applications="nextcloud dokuwiki kolab"

Parsing attributes for each application

I will iterate over the list of applications.

for application in $applications; do

Assign attributes (like server, username, ...) using application_attribute variable (values like nextcloud_server, nextcloud_username, ... depending on the application name) to define target variable name and read value using ${!application_attribute} construct. Use default value if it is empty.

  # define attributes for server/application
  for attribute in $attributes; do
    application_attribute="${application}_${attribute}"
    default_attribute="default_${attribute}"
    if [ -n "${!application_attribute}" ]; then
      eval "${attribute}"="${!application_attribute}"
    else
      eval "${attribute}"="${!default_attribute}"
    fi
  done

Perform desired actions using short attribute names.

  # perform an action
  if [ -n "$bastion" ]; then
    bastion_param="-J ${busername}@${bastion}"
  else
    bastion_param=""
  fi
	echo -n "$server: "
  ssh $bastion_param $server -l $username "bash -c 'df -h --output=avail $partition | sed 1d'"

End of the application loop is self-explanatory.

done

Additional notes

source configuration and additional functions to keep these parts separate from main shell script.