简体   繁体   中英

not allow multiple option in getopts of bash script

Having bash script as follows

#! /bin/bash

usage()
{
  echo -e "need help!"  
}

while getopts ":a:b:h" OPTION
do
     case $OPTION in
     a)
        printf "a option with value %s\n" $OPTARG
        ;;
     b)
        printf "b option with value %s\n" $OPTARG
        ;;
     h)
        usage
        ;;
     ?)
        echo -e "No option selected"
       ;;
    esac
done

exit 0

Above script run fine with different option but i wanted to extend it to not allow to pass multiple option at same time like as following argument

$ ./test.bash -a 1 -b 2
a option with value 1
b option with value 2

should be not valid means some way it give me error like wrong syntax i achieved it by as follows but it seems to long it is as follow

#! /bin/bash
usage()
{
  echo -e "need help!"  
}

let "a_count=0"
let "b_count=0"
MY_ARG=""
while getopts ":a:b:h" OPTION
do
     case $OPTION in
     a)
        let a_count=1
        MY_ARG=$OPTARG
        ;;
     b)
        let b_count=1
        MY_ARG=$OPTARG
        ;;
     h)
        usage
        ;;
     ?)
        echo -e "No option selected"
       ;;
    esac
done

[[ $a_count -eq 1 ]] && [[ $b_count -eq 1 ]] && echo "wrong command sytax" && exit 0

[[ $a_count -eq 1 ]] &&  printf "a option with value %s\n" $MY_ARG

[[ $b_count -eq 1 ]] &&  printf "b option with value %s\n" $MY_ARG

exit 0

run like

$ ./test.bash -a 1 -b 2
wrong command sytax

But i want to finish validation in while..loop of getopts . Also this validation not works for following command

./test.bash -a -b 
a option with value -b

any one have batter idea how to use getopts for this type validation?

you've almost got it. The : after the a and after the b say that they take an argument, so your example with -a -b is actually valid, saying "There is option a with value -b".

If you really just want "-a or -b and then an argument", you probably don't need getopts at all, but should do:

[ "$1" == "-a" ] && printf "a option with value %s\n" $2
[ "$1" == "-b" ] && printf "b option with value %s\n" $2

any one have batter idea how to use getopts for this type validation?

well, actually, you're explicitly telling geptopts that -a and -b are not boolean parameters, but parameters that take an extra argument. The argument parser cannot tell whether the argument following -a is a parameter or its own argument, and thus they consider [-a ] [-b ] as syntax.

The best way, would actually be to have a different boolean parameter that matches the use case when you do not want an argument for -a and -b .

Though, it won't help you with your issue trying to have parameters with argument or boolean, but for the argument syntax checking you can try docopt which has a nicer way to create command line interface. You focus on doing the --help documentation, it parses it to build your parameter/argument parser. eg:

eval "$(docopts -V - -h - : "$@" <<EOF
Usage: myscript [(-a <foo> | -b <bar> | -abool | -bbool)]

      -a <foo>   The A option.
      -b <bar>   The B option.
      -abool     The A bool
      -bbool     The B bool
      --help     Show help options.
      --version  Print program version.
----
myscript 0.0.0
Copyright (C)20.. Your Name
License...
)"

if $a ; then
    echo "a option! with $a"
fi

if $b ; then
    echo "b option! with $b"
fi

if $abool ; then 
    echo "abool option!"
fi


if $bbool ; then 
    echo "bbool option!"
fi

This is not quite perfect because it will always process the first switch, but it does place an exit inside the while loop which is in keeping with your design requirement. It may give you an idea how to finish it.

#!/bin/bash

usage()
{
  echo -e "need help!"
}

while getopts "a:b:h" OPTION
do
     case $OPTION in
     a)
       aflag=1
       aval=$OPTARG
       if [ ! -z "$bflag" ]
       then
         printf "ERROR: cant use both -a and -b\n"
         exit 1
       fi
       ;;
    b)
       bflag=1
       bval=$OPTARG
       if [ ! -z "$aflag" ]
       then
        printf "ERROR: cant use both -a and -b\n"
        exit 1
       fi
       ;;
    h) usage ;;
    ?) printf "ERROR" ; exit 1 ;;
   esac
done

if [ ! -z "$aflag" ]
then    
  printf "a option with value %s $aval\n"
elif [ ! -z "$bflag" ]
then
  printf "b option with value %s $bval\n"
fi

exit 0

If you still want to use the getopts I would use bash built-in variable for the arguments count $# to detect wrong number of arguments passed:

#! /bin/bash

usage()
{
  echo -e "need help!"  
}

# Check if number of arguments is greater than 2 as "-a1" (one arg) and "-a 2" are correct.
# You might want to check for other wrong inputs.
if [ $# > 2 ]
then
    echo "Some warning t o the user or"
    usage
    exit 1
fi

while getopts ":a:b:h" OPTION
do
     case $OPTION in
     a)
        printf "a option with value %s\n" $OPTARG
        ;;
     b)
        printf "b option with value %s\n" $OPTARG
        ;;
     h)
        usage
        ;;
     ?)
        echo -e "No option selected"
       ;;
    esac
done

exit 0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM