1

I have a script that starts with getopts and looks as follows:

USAGE() { echo -e "Usage: bash $0 [-w <in-dir>] [-o <out-dir>] [-c <template1>] [-t <template2>] \n" 1>&2; exit 1; }

if (($# == 0))
then
    USAGE
fi

while getopts ":w:o:c:t:h" opt
do
    case $opt in
        w ) BIGWIGS=$OPTARG
        ;;
        o ) OUTDIR=$OPTARG
        ;;
        c ) CONTAINER=$OPTARG
        ;;
        t ) TRACK=$OPTARG
        ;;
        h ) USAGE
        ;;
        \? ) echo "Invalid option: -$OPTARG exiting" >&2
       exit
        ;;
        : ) echo "Option -$OPTARG requires an argument" >&2
        exit
        ;;
    esac
done

more commands etc

echo $OUTDIR
echo $CONTAINER

I was doing some testing on this script and at some stage, I didn't need/want to use the -c argument [-c ]. In other words, I was trying to test another specific part of the script not involving the $CONTAINER variable at all. Therefore, I simply added # in front of all commands with the $CONTAINER and did some testing which was fine.

When testing the script without using $CONTAINER, I typed:

bash script.bash -w mydir -o myoutdir -t mywantedtemplate

However, I was wondering, given my getopts command I didn't get a warning. In other words, why did I not get a warning asking for -c argument. Is this possible? Does the warning only occur if I type:

bash script.bash -w mydir -o myoutdir -t mywantedtemplate -c

UPDATE

After doing some testing, I think that is it:

  • If you don't explicitly write "-c", getopts won't "ask" you for it and give you an error (unless your script is doing something with it - i.e. if you haven't put # in front of each command using this argument)
  • You only get an error if you put "-c " and nothing else

Is this correct? Presumably what I did was "bad practise" and should be avoided: when testing, I should just remove the c: from the getopts command entirely.

I guess what I am asking is: when you tell getopts about the arguments (the "while" line in my script), are we saying: these are the options you can expect and the ones followed by a ":" should have argument with them. BUT they don't HAVE to be given. I.e. you can expect an c option with an argument but don't throw an error if you are not given the c option at all.

  • I'm not exactly sure what you mean with "asking for -c argument". You refer to a version of the code with $CONTAINER commented out, so it might be better to just show the exact situation you mean. What's the code, how did you call it, what did you expect to happen, what happened instead? – ilkkachu Sep 14 '18 at 9:24
  • What I was trying to ask is how does getopts react when I type: bash script.bash -w hello -o hello2 -t hello3 -c hello4 VS bash script.bash -w hello -o hello2 -t hello3 -c VS bash script.bash -w hello -o hello2 -t hello3 In other words, does getopts not mind if I just don't provite -c at all when I do some testing? I'm just trying to understand how it works – m93 Sep 14 '18 at 9:26
1

The getopts utility does not know about mandatory options, only about what options are allowed (and what options out of these should take an option argument). If you want to enforce mandatory options, you would have to do so with your own tests in or after the option parsing loop.

The getopts utility does not do this because options can have more complex relationships such as some options conflicting, some options requiring the presence of other options etc. This is left to to the script author to sort out with their own logic.

  • Great that makes sense :) I was just worried that I had somehow made a bad mistake but assuming that the options were not mandatory. Thanks! – m93 Sep 14 '18 at 9:32
1

I'm not exactly sure what it is you're asking, but what getopts does, is that it parses the command line that was already given to the program, and pops out the options that it sees, one-by-one, in a format that's somewhat easy for the program code to handle. It does have the option of printing errors for options it does not know, but that's all it does.

It doesn't really "ask" anything from anyone as the command line is already fixed when getopts is called. There's no interaction unless the rest of the program implements it.

It also doesn't, and can't know what options are required for the program to function (there's no syntax for that in the "optstring" getopts takes as argument). The usual case is that no options are required (think ls, rm, vi ...), and in the cases where you do have required options, you can check for them manually in the script.

Consider this example:

#!/bin/bash

opt_a=
opt_b=
while getopts 'a:bc' opt; do
    case $opt in
        a) opt_a=$OPTARG;;
        b) opt_b=1;;
    esac
done

if [ -z "$opt_a" ]; then
    echo "option a was NOT given, exit."
    exit 1;
fi
echo "do something with a='$opt_a' b=$opt_b"

The script explicitly checks if a was given. Without the check, the program would happily continue without it. getopts is also told to accept c as an option, and doesn't give an error for it. The script just ignores it completely, since I didn't put a c) or a *) case in there. There's no way for getopts to know that this particular option will be ignored.

Note that the customary meaning of square brackets in a usage hint is to tell an option is optional, so if you mean that all of -w, -o, -c, -t should be given to your script, I'd suggest dropping the brackets.

  • Thanks very much! That if statement check will be very useful for me! – m93 Sep 14 '18 at 10:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.