0

I am struggling to make a script have this behavior:

  • I want to pass options like this ./script -ab is the same as ./script -a -b
  • And have this logic: "a & b -> c", "a & c -> c", "b & c -> c" (single option is function as normal)
  • Also I want this script to fall back to a function (e.g help function) when calling the script without any option

This is some example:

#!/usr/bin/env bash if [[ ${#} -eq 0 ]]; then echo "Default function" else while getopts ":a:b:c:" opt; do case ${opt} in a) echo "a" ;; b) echo "b" ;; c) echo "c" ;; *) echo -e "Invalid option: ${@}" ;; esac done fi 

Any help is appreciated

1
  • 2
    You've declared that all of your options require an argument (by writing a: instead of a), but in your examples you're not passing arguments. This is probably the source of most of your problems.
    – larsks
    CommentedAug 10, 2022 at 13:12

2 Answers 2

2

It's probably most straightforward to just set flags for each of the options, and then after the loop check if the flags for both A and B are set and enable C if they are.

But you could model this as a bitmap with one bit each for A and B, and C being the state where both bits are set. So A=01, B=10, C=11 plus the default state with both bits cleared. (The states correspond to default=0, A=1, B=2, C=3 in decimal or hex.) Then just set the appropriate bits when the corresponding options are seen.

Like so:

#!/usr/bin/env bash mode=0 while getopts "abc" opt; do case ${opt} in a) mode=$(( mode | 0x01 )) ;; # set rightmost bit b) mode=$(( mode | 0x02 )) ;; # set leftmost bit c) mode=$(( mode | 0x03 )) ;; # set both bits *) exit 1 ;; esac done echo "chosen mode is $mode (0 = default, 1 = a, 2 = b, 3 = c)" 

Note that you mention -A and -b in the text, but your script has a and b. getopts cares about the letter case, so those aren't the same. Also the colons in getopts a:b:c: mark the options as taking arguments, but you don't seem to need that.

3
  • 1
    I don't know really, but you likely want to use 0x04 rather than 0x03 for c if you're aiming to use $mode as a bitmask, to capture the various combinations of the three options in the values 0 through to 7.
    – Kusalananda
    CommentedAug 10, 2022 at 17:38
  • 1
    @Kusalananda, no, they said they want A+B to give C, and that happens with binary or if A and B are distinct bits and C is the combination of the two. I definitely don't want C to be a third bit because then it won't or together with either of the two others. (I can't edit the answer to show all the combinations right now, someone else may do it.)
    – ilkkachu
    CommentedAug 11, 2022 at 18:11
  • Ah, I wasn't reading carefully enough. You're correct. I got too interested in the option processing and disregarded the required interaction between the options.
    – Kusalananda
    CommentedAug 11, 2022 at 22:05
0

(Edited to handle new request in the question)

You're very close. Below is the kind of thing I've done. It looks a bit complex at first, but it's a sequence of steps setting the defaults, parsing the command line, checking for bad option values or combinations, then script main routine after:

#!/usr/bin/env bash # defaults for options help=n opt_a=1 opt_b=production opt_c=0 # if no options from my user, print help message only if [[ $# -lt 1 ]]; then help=y; fi # parse command line while getopts ':ha:b:c' OPTION; do case "${OPTION}" in h) help=y ;; a) opt_a="${OPTARG}" ;; b) opt_b="${OPTARG}" ;; c) opt_c=1 ;; \?) echo "$0: Error: Invalid option: -${OPTARG}" >&2 ; exit 1 ;; :) echo "$0: Error: option -${OPTARG} requires an argument" >&2 ; exit 1 ;; esac done shift $((OPTIND - 1)) # request for help overrides other actions if [[ ${help} == 'y' ]]; then # put code here to print a USAGE message exit 0 fi # check and error out on bad options from my user # check -b: case "$opt_b" in production) ;; staging) ;; qa) ;; *) echo "$0: Error: unknown argument -b \"${opt_b}\", exiting" >&2 ; exit 1 ;; esac # script does its work starting from here 

Invoking with script-name -c -b qa will parse the options -b and -c as expected, and script-name -cb qa will also work.

I gave only one example of checking the options (to keep the answer simple); normally there would be more code to check each option and respond to legal and illegal combinations of options. I usually tuck those lines of code into a subroutine so they aren't in the middle of the script's main work flow.

0

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.