Search code examples
bashcommand-line-argumentsgetopts

Order of getopts when no argument is passed to option


My problem is that when I use the snippets below the script chokes up the order when I do not give an argument to option. If I do include arguments all is well and I can enter options in any order.

How can I ensure that the different options (-s and -f) are mapped correctly to their variables using getopts?

Please see the example below.

./script.bash -ftestfile -s0

search flag: 0
file: testfile

./script.bash -s0 -ftestfile

search flag: 0
file: testfile

So far so good..

The issue hits when the f option does not carry an argument (testfile in the examples). It seems getopts is no longer able to recognize that -s should be inputsearch and -f is still inputfile.

./script.bash -f -s0

search flag: 
file: -s0

The magic below here

s=0
while getopts :s:f:ih option
do
case "${option}" in
        s) inputsearch=${OPTARG};;
        f) inputfile=${OPTARG};;
        h) display_help; exit 1;;
        ?) display_help; exit 1;;
esac
done

# crap validation (must contain some option and option cant simply be "-" or "--"
if [ -z "$1" ] || [ "$1" = "-" ] || [ "$1" = "--" ]
then
        display_help
        exit 1
fi

#this fails
if [[ $inputsearch -gt 1 ]] || [[ -z $inputfile ]]
then
        display_help
        exit 1
else
        echo "search flag: $inputsearch"
        echo "file: $inputfile"
fi

Thanks for your input!


Solution

  • Sorry to say, that is how it is with simple getopts. If it expects an argument it just takes the next word as the argument. You only get an error if there are no more arguments.

    You could error-check the argument before your case statement? Something like below, but you risk skipping a valid argument, for example a negative number.

    do
      if [ "${OPTARG:0:1}" == "-" ] 
      then 
        echo ERROR: argument ${OPTARG} to -${option} looks like an option
        exit 1
      fi
    
      case "${option}" in
    

    You could easily add more error checking that ${OPTARG:1:1} is actually in your option string, and perhaps that ${option} expects an argument.