0

My script.sh usage:

./work.sh [options] parm_1 parm_2 parm_3 parm_4

the options:

-y year
-n number
-1 (flag, no parameters)
-2 (flag, no parameters)

i would like a mutual exclusion between -1 and -2 flags, so that if -1 is specified, -2 cannot be used and throw an error and viceversa is it possible to implement this with getopts?

codeforester
  • 39,467
  • 16
  • 112
  • 140
DamienzOnly
  • 88
  • 1
  • 10
  • 6
    Sure. Simply use your regular getopts processing loop assigning to `FLAG1` and `FLAG2` accordingly. After the loop, check if both are set and if so, error out. – Jens Apr 04 '18 at 21:01
  • @Jens i actually don't know how to implement that, would you help me with the code and the while loop? thank you very much – DamienzOnly Apr 04 '18 at 21:03
  • 4
    Show what you've got that works except that it allows both `-1` and `-2`. Then we can help you fix it so that you don't allow both. That is, show us an MCVE ([MCVE]). – Jonathan Leffler Apr 04 '18 at 21:09
  • @JonathanLeffler it's not about my code, it's about the implementation and the basics of bash, i don't have any code yet, but i need my script to tell the user that if he specifies one of the flags then he can't use the other one, and viceversa – DamienzOnly Apr 04 '18 at 21:14
  • OK; if you can't show us how you use the basic `getopts` loop, we can't help you fix it, can we? What you want is easily done — when you have the basic code in place. You've been [told](https://stackoverflow.com/questions/49660245/bash-prevent-the-usage-of-two-flags-simultaneously-when-running-script?noredirect=1#comment86330263_49660245) how to do it. We don't know what naming conventions you want to use, etc. You should show us that you know how to use `getopts` at all. There are a number of examples of that on SO that you can use as a basis. – Jonathan Leffler Apr 04 '18 at 21:18

1 Answers1

4

getopts is an option parsing tool; it doesn't handle logic and semantics (the meaning of options, required options or forbidden combos, etc). Those go in the code around getopts (as @Jens suggested in a comment). Here's a simple example:

# Default values:
flag1="false"    # Note: "false" is just a text string, this is a cheat.
flag2="false"    # See note at end.
year=2001
number=42    # because 42 is the correct default number

# Parse the supplied options
while getopts "y:n:12" OPT; do
    case "$OPT" in
        y)
            year=${OPTARG}
            ;;
        n)
            number=${OPTARG}
            ;;
        1)
            flag1="true"
            ;;
        2)
            flag2="true"
            ;;
        *)
            echo "Usage: $0 [-y year] [-n number] [-1|-2]" >&2
            exit 1
            ;;
    esac
done
shift $((OPTIND-1))

# Enforce rules about option combos
if $flag1 && $flag2; then
    echo "$0: The options -1 and -2 cannot be specified together." >&2
    exit 1
fi

This is really just a bog-standard invocation of getopts to parse options, folowed by an if statement to enforce the rule that -1 and -2 can't be used together. That's all there is to it.

Note that I'm treating flag1 and flag2 as boolean variables, but there's really no such thing in shell syntax; they're actually just strings. That happen to correspond to commands. That happen to work in a semi-intuitive way in if statements. But it's a cheat, so don't mistake them for real boolean variables. See here for some more info.

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • Is it worth showing that `year` and `number` should be preset to empty to avoid accidentally picking up some environment variable from some other script? The use of `true` and `false` is clever. – Jonathan Leffler Apr 04 '18 at 21:21
  • @JonathanLeffler Maybe, but how I'd write that depends a lot on how those options were used. I.e. they might have default values, or I might need to set other "booleans" to track whether they'd been specified at all, or they might just be different ways of specifying a single variable (and whichever was specified last should take precedence), or... I figured I'd just leave their handling bare-minimum, to be filled out based on the actual situation. But you're right that *something* should be done, so I'll go ahead and add defaults. – Gordon Davisson Apr 04 '18 at 21:27
  • "true" and "false" don't behave just as strings in the `if` clause. Replace them with "True" and "False" to see the difference. – karakfa Apr 04 '18 at 21:31
  • 1
    @karakfa They're strings *that correspond to the names of commands*. There are commands named "true" and "false", but no commands named "True" or "False", hence the difference. Unless you're on a case-insensitive filesystem, in which case the capitalized versions will work as well. – Gordon Davisson Apr 04 '18 at 21:37
  • I know that you know and very nice solution by the way but the comment in the answer is confusing (or seem like magic) for the novice. – karakfa Apr 04 '18 at 21:40