POSIX convention is that non-option arguments to a command must come after all options and option arguments. The POSIX getopts
utility is designed around this convention, so if you don't want to insist on conventional argument order then getopts
is not a good fit. It might still be possible to make getopts
work in that case, but I wouldn't try to do so.
If you are willing to depend on the GNU version of the getopt
utility (not to be confused with getopts
, with an s
), then it can accommodate you. By default, it recognizes options anywhere on the command line, including after non-option arguments. That might look like this:
args=$(getopt --name "$0" --options n:o:x: -- "$@")
eval set -- "$args"
while [[ $# -gt 0 ]]; do
case "$1" in
-n) n_argument=$2; shift 2;;
-o) o_argument=$2; shift 2;;
-x) x_argument=$2; shift 2;;
*)
# Handle non-option argument $1 ...
shift
;;
esac
done
But note that you can do much the same without getopt
. What getopt
(or getopts
) does for you is:
- normalize ganged options (
-abc
equivalent to -a -b -c
; only for options that do not require arguments)
- normalize option / argument separation (
-xfoo
equivalent to -x foo
when option x
takes an argument)
- recognize and accommodate the significance of argument
--
for indicating that only non-option arguments follow
- recognize errors in the arguments, especially the omission of option arguments where they are required
- similar to the above for GNU-style long options (GNU
getopt
only)
If you're not interested in any of that, or if you're willing to roll your own for the ones of those that you want, or if you can't rely on having the GNU version of getopt
then you can use a loop similar to the above without first using getopt
to massage the argument list, and without involving getopts
.