13

I have a simple script (below) that has mutually exclusive arguments.

The arguments for the script should be ./scriptname.sh -m|-d [-n], however, a user can run the script with ./scriptname.sh -m -d which is wrong.

Question: how can I enforce that only one of the mutually exclusive arguments have been provided by the user?

#!/bin/sh

usage() {
   cat <<EOF
Usage: $0 -m|-d [-n]
where:
    -m create minimal box
    -d create desktop box
    -n perform headless build
EOF
   exit 0
}

headless=
buildtype=

while getopts 'mdnh' flag; do
  case "$flag" in
    m) buildtype='minimal' ;;
    d) buildtype='desktop' ;;
    n) headless=1 ;;
    h) usage ;;
    \?) usage ;;
    *) usage ;;
  esac
done

[ -n "$buildtype" ] && usage
pevik
  • 4,523
  • 3
  • 33
  • 44
Chris Snow
  • 23,813
  • 35
  • 144
  • 309
  • Someone else has been asking this...hold on, I'll find it...Ah, there it is...[How to use mutually exclusive flags in your shell — stuck with `getopts`?](http://stackoverflow.com/questions/21695565/how-to-use-mutually-exclusive-flags-in-your-shell-stuck-with-getopts) It was even in the list of related questions. You could also look at [Using `getopts` in bash shell script to get long and short command line options](http://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options/). That covers a lot of territory. – Jonathan Leffler Feb 12 '14 at 07:36
  • I did search on google and scan the recommended questions, but didn't think these links were relevant. Hopefully, my question title will help others who are also inadequate at searching (like me) :) – Chris Snow Feb 12 '14 at 07:49

1 Answers1

15

I can think of 2 ways:

Accept an option like -t <argument> Where argument can be desktop or minimal

So your script will be called as:

./scriptname.sh -t desktop -n

OR

./scriptname.sh -t minimal -n

Another alternative is to enforce validation inside your script as this:

headless=
buildtype=

while getopts 'mdnh' flag; do
  case "$flag" in
    m) [ -n "$buildtype" ] && usage || buildtype='minimal' ;;
    d) [ -n "$buildtype" ] && usage || buildtype='desktop' ;;
    n) headless=1 ;;
    h) usage ;;
    \?) usage ;;
    *) usage ;;
  esac
done
pevik
  • 4,523
  • 3
  • 33
  • 44
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Many thanks! Btw - I noticed and fixed a typo in the question, `buildttype` should have been `buildtype`. – Chris Snow Feb 12 '14 at 07:57
  • How to adapt the code if the 2 options are no mandatory, but if used, should be used only one. My code is similar but my variable is not empty as default, it is `dir=pwd` and the options `m` or `d` would redefine it. – Sigur Dec 24 '16 at 14:16
  • Thankyou for the answer, but could you explain further why [ -n "$buildtype" ] validates these to be mutually exclusive? – openCivilisation Nov 30 '19 at 11:59
  • 1
    `-n "$buildtype"` will return success if `$buildtype` is non-empty. – anubhava Nov 30 '19 at 12:03