Roger Robinson
Roger Robinson

Reputation: 21

BASH getopts Multiple Scripts with Same Options

I have a series of BASH scripts.

I am using getopts to parse arguments from the cmd line (although open to alternatives).

There are a series of common options to these scripts call this options set A ie queue, ncores etc.

Each script then has a series of extra options ie set B1,B2,B3.

What I want is for script

"1 to be able to take options  A+B1"
"2 to be able to take options  A+B2"
"3 to be able to take options  A+B2"

But I want to be able to store the code for options A in a central location (library/function) with having to write out in each script.

What I want is a way to insert generic code in getopts. Or alternatively a way to run getopts twice.

In fact I've done this by having getopts as a function which is sourced.

But the problem is I cant get the unrecognised option to work them. I guess one way would be to remove the arguements from options A from the string before passing to a getopts for B1, B2 , B3 etc ?

Thanks Roger

Upvotes: 1

Views: 505

Answers (1)

UrsaDK
UrsaDK

Reputation: 865

That's a very nice question, to answer which we need to have a good understanding of how getopts works.

The key point here is that getopts is designed to iterate over the supplied arguments in a single loop. Thus, the solution to the question is to split the loop between different files rather then running the command twice:

#!/usr/bin/env bash
# File_1

getopts_common() {
    builtin getopts ":ab:${1}" ${2} ${@:3} || return 1
    case ${!2} in
        'a')
            echo 'a triggered'
            continue
            ;;
        'b')
            echo "b argument supplied -- ${OPTARG}"
            continue
            ;;
        ':')
            echo "MISSING ARGUMENT for option -- ${OPTARG}" >&2
            exit 1
            ;;
    esac
}

#!/usr/bin/env bash
# File_2
# source "File_1"

while getopts_common 'xy:' OPTKEY ${@}; do
    case ${OPTKEY} in
        'x')
            echo 'x triggered'
            ;;
        'y')
            echo "y argument supplied -- ${OPTARG}"
            ;;
        '?')
            echo "INVALID OPTION -- ${OPTARG}" >&2
            exit 1
            ;;
        ':')
            echo "MISSING ARGUMENT for option -- ${OPTARG}" >&2
            exit 1
            ;;
        *)
            echo "UNIMPLEMENTED OPTION -- ${OPTKEY}" >&2
            exit 1
            ;;
    esac
done

Implementation notes

We start with File_2 since that's where the execution of the script starts:

  • Instead of invoking getopts directly, we call it via it's proxy: getopts_common, which is responsible for processing all common option.

  • getopts_common function is invoked with:

    1. A string that defines which options to expect, and where to expect their arguments. This string only covers options defined in File_2.

    2. The name of the shell-variable to use for option reporting.

    3. A list of the command line arguments. (This simplifies accessing them from inside getopts_common function.)

Moving on to the sourced file (File_1) we need to bear in mind that getopts_common function runs inside the while loop defined in File_2:

  • getopts returns false if there is nothing left to parse, || return 1 bit insures that getopts_common function does the same.

  • The execution needs to move on to the next iteration of the loop when a valid option is processed. Hence, each valid option match ends with continue.

  • Silent error reporting (enabled when OPTSPEC starts with :) allows us to distinguish between INVALID OPTION and MISSING ARGUMENT. The later error is specific to the common options defined in File_1, thus it needs to be trapped there.

For more in-depth information on getopts, see Bash Hackers Wiki: Getopts tutorial

Upvotes: 1

Related Questions