Bash Script with a Lib for Named Parameters

When working on Bash scripts, it is often useful to make them more flexible by using parameters. In a previous blog post, I demonstrated how to add named parameters to a single script. However, if you want to apply this feature to multiple script files, it might make sense to move the code to a separate library file and include it in each script as needed. In this blog, I'll show you how to do this.

Initial setup

To get started, create a file called /lib/arguments.sh and another file called test.sh, and make them executable using the chmod command:

mkdir -p lib
touch ./lib/arguments.sh test.sh
chmod +x ./lib/arguments.sh test.sh

Next, open test.sh in your preferred text editor and set it up as follows:

#!/usr/bin/env bash

set -eo pipefail

script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
source "$script_dir/lib/arguments.sh"

Next, we can open up the ./lib/arguments.sh and set it up as well:

#!/bin/bash

set -eo pipefail

Named arguments function

Add the following parse_input_args function to your lib.sh file. This will parse all the arguments and convert them to variables:

function parse_input_args() {
    while [ $# -gt 0 ]; do
    if [[ $1 == "--help" || $1 == "-h" ]]; then
        usage
        exit 0
    elif [[ $1 == "--version" || $1 == "-v" ]]; then
        version
        exit 0
    elif [[ $1 == "--"* ]]; then
        v="${1/--/}"
        export "$v"="$2"
    fi
    shift
    done
}

Note how this function also implements --help and --version. The --help will call the usage function. The --version will call the version function. More on that in the example here.

With this code you're able to set variables in your calling script. Let's declare two variables in our test.sh and see how it works:

declare env="" tag="nothing"
parse_input_args "$@"

echo "Env: $env"
echo "Tag: $tag"

Let's test what this does:

$ ./test.sh
Env:
Tag: nothing

$ ./test.sh --env dev --tag hello
Env: dev
Tag: hello

$ ./test.sh --help
lib.sh: line 9: usage: command not found

Required parameter validation

Often you'll need parameters not to be empty, so let's add that to our lib.sh as well:

function function_exists() {
    declare -f -F "$1" > /dev/null
    return $?
}

function die {
    printf "Script failed: %s\n\n" "$1"
    exit 1
}

function ensure_required_input_arg(){
    name=$1
    value=$2

    if [[ -z "$value" ]]; then
        function_exists usage && usage
        die "Missing parameter $name"
    fi
}

Add it to the script like this:

ensure_required_input_arg "--env" "$env"
ensure_required_input_arg "--tag" "$tag"

Let's test:

$ ./test.sh --env dev
Env: dev
Tag: nothing

$ ./tests.sh --env dev --tag
Script failed: Missing parameter --tag

We could improve this a bit with writing a special usage function that explains what the script needs a input.

Final arguments.sh file

Our complete Bash file now looks like this:

#!/usr/bin/env bash

set -eo pipefail

function parse_input_args() {
    while [ $# -gt 0 ]; do
    if [[ $1 == "--help" || $1 == "-h" ]]; then
        usage
        exit 0
    elif [[ $1 == "--version" || $1 == "-v" ]]; then
        version
        exit 0
    elif [[ $1 == "--"* ]]; then
        v="${1/--/}"
        export "$v"="$2"
    fi
    shift
    done
}

function function_exists() {
    declare -f -F "$1" > /dev/null
    return $?
}

function die {
    printf "Script failed: %s\n\n" "$1"
    exit 1
}

function ensure_required_input_arg(){
    name=$1
    value=$2

    if [[ "$value" == "" ]]; then
        function_exists usage && usage
        die "Missing parameter $name"
    fi
}

A more elaborate example

So, now that we have a library in place, let's create a bigger script that has a usage and version functions and some required parameters:

#!/usr/bin/env bash

set -eo pipefail

script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
source "$script_dir/lib/arguments.sh"

program_name=$0
program_version="0.0.1"
function usage {
    echo ""
    echo "Performs a shallow clone of a GitHub repository with a GitHub app."
    echo ""
    echo "usage: $program_name --repo string --branch string [--help] [--version]"
    echo ""
    echo "  --repo string    name of the service"
    echo "                   (example: KeesCBakker/keestalkstech-code-gallery)"
    echo "  --branch string  tag of the image to deploy"
    echo "                   (example: main)"
    echo "  --version        shows the version of the script."
    echo "  --help           shows this help."
    echo ""
}

function version {
    echo "$program_version"
}

parse_input_args "$@"

ensure_required_input_arg "--repo" "$repo"
ensure_required_input_arg "--branch" "$branch"

Enjoy!

Changelog

  • Added a better example and support for --version, -v and -h.
  • Initial article.
expand_less brightness_auto