Search code examples
bashparametersscriptingargumentsgetopts

Is there a way in bash script to have an option to give an argument but it shouldn't a must?


I have a scenario where i would like to assign an option a default value but a user can decide to give it another argument:

Here is an example

 check_param() {

        for arg in "$@"; do
                shift
                case "$arg" in
                        "--force") set -- "$@" "-f" ;;
                        "--type") set -- "$@" "-t" ;;
                        "--help") set -- "$@" "-h" ;;
                        "--"*) echo "Unknown parameter: " $arg; show_help; exit 1 ;;
                        *) set -- "$@" "$arg"
                esac
        done

        # Standard Variables
        force=0
        type="daily"

        OPTIND=1
        while getopts "hft:v" opt
        do
                case "$opt" in
                        "f")    force=1 ;;
                        "t")    type=${OPTARG} ;;
                        "h")    show_help; exit 0 ;;
                        "?")    show_help; exit 1 ;;
                esac
        done
        shift $(expr $OPTIND - 1) # remove options from positional parameters

From the above example, i would like when the user gives the parameter -t without any argument to apply the default value which is daily , and the user can also use parameter -t with any other argument and that will be checked later in code.

The problem is now the parameter -t must be given an argument due to the colon, but i kinda need for it to do both, with or without argument.

Thanks in advance for any explanations or links to any article that can help.

So according to a suggestion i got Here is the test result

check_param() {


        ## Standard Variablen der Parameter
        force=0
        type="daily.0"

        ## Break down the options in command lines for easy parsing
        ## -l is to accept the long options too
        args=$(getopt -o hft::v -l force,type::,help -- "$@")
        eval set -- "$args"

        ## Debugging mechanism
        echo ${args}
        echo "Number of parameters $#"
        echo "first parameter $1"
        echo "Second parameter $2"
        echo "third parameter $3"

        while (($#)); do
                case "$1" in
                -f|--force) force=1; ;;
                -t|--type) type="${2:-${type}}"; shift; ;;
                -h|--help) show_help; exit 0; ;;
                --) shift; break; ;;
                *) echo "Unbekannter Parameter"; exit 1; ;;
                esac
                shift
        done
echo ${type}

}

check_param $@

echo ${type}

The output:

sh scriptsh -t patch.0
-t '' -- 'patch.0'
Number of parameters 4
first parameter -t
Second parameter
third parameter --
daily.0
daily.0

It still didn't assign the value patch to the variable type


Solution

  • Is there a way in bash script to have an option to give an argument but it shouldn't a must?

    Yes, there is a way.

    getopts does not supports optional arguments. So... you can:

    • roll your own bash library for parsing arguments or
    • use another tool that has support for optional arguments.

    A common tool is getopt that should be available on any linux.

    args=$(getopt -o hft::v -l force,type::,help -- "$@")
    eval set -- "$args"
    while (($#)); do
       case "$1" in
       -f|--force) force=1; ;;
       -t|--type) type="${2:-default_value}"; shift; ;;
       -h|--help) echo "THis is help"; exit; ;;
       --) shift; break; ;;
       *) echo "Error parsgin arguments"; exit 1; ;;
       esac
       shift
    done
    

    getopt handles long arguments and reorders arguments, so you can ./prog file1 -t opt and ./prog -t opt file1 with same result.