getopts automatically breaks the while loop as soon as it detects a parameter without a dash (not including the argument given to the dash parameters that take arguments). The POSIX standard is to have dotted options first and then have files. There's also none of that -- and + shit too. It is simple and simple.
However, Linux is not compatible with Unix or POSIX. It's just that GNU utilities are "better" than standard Unix utilities. More features, extra features and handling things a little differently.
On Linux, command line options may appear after files in many GNU utilities.
For instance:
$ cp -R foo bar
Work on my certified Unix Mac OS X and Linux, however
$ cp foo bar -R
Only works with Linux.
If you want getopts work as many Linux utilities, you need to do a little work.
First you must process your arguments yourself and not be dependent on $OPTIND to $OPTIND them. You also need to verify that you have an argument.
I came up with this as an example of what you want.
#! /bin/bash while [[ $* ]] do OPTIND=1 echo $1 if [[ $1 =~ ^- ]] then getopts :a:b:cd parameter case $parameter in a) echo "a" echo "the value is $OPTARG" shift ;; b) echo "b" echo "the value is $OPTARG" shift ;; c) echo "c" ;; d) echo "d" ;; *) echo "This is an invalid argument: $parameter" ;; esac else other_arguments="$other_arguments $1" fi shift done echo "$other_arguments"
Now I loop until $* is set. (Maybe I should use $@ ?) I should do a shift at the end of the loop. I also reset $OPTIND to 1 every time, because I transfer the arguments myself. $OPTARG is still installed, but I have to do another shift to make sure everything works.
I also need to check if the argument starts with a dash or not using the regular expression in the if .
Basic testing shows that this works, but I cannot say that this is a mistake, but it gives you an idea of how you need to process your program.
There are still many features that you get from getopts , but this requires a bit more work.