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.sh and another file called test.sh, and make them executable using the chmod command:

touch lib.sh test.sh
chmod +x lib.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.sh"

Next, we can open up the test.sh and set it up as well:

#!/usr/bin/env 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" ]]; then
        usage
        exit 0
    elif [[ $1 == "--"* ]]; then
        v="${1/--/}"
        export "$v"="$2"
    fi
    shift
    done
}

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

The implementation supports a help parameter out of the box: it will call the usage function. More on that here.

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 lib.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" ]]; then
        usage
        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
}

And we can "include" it like this:

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

Enjoy!

expand_less