You can iterate between both kinds of argument, I think.
I think this does what you want, and allows you to use --
to prevent the following arguments being interpreted as options.
mandatory=()
while [ $# -gt 0 ] && [ "$1" != "--" ]; do
while getopts "a:x:" opt; do
case $opt in
a) echo "option a set: $OPTARG" ;;
x) echo "option x set: $OPTARG" ;;
\?) echo "Invalid option: -$OPTARG" >&2; exit 1;;
esac
done
shift $((OPTIND-1))
while [ $# -gt 0 ] && ! [[ "$1" =~ ^- ]]; do
mandatory=("${mandatory[@]}" "$1")
shift
done
done
if [ "$1" == "--" ]; then
shift
mandatory=("${mandatory[@]}" "$@")
fi
echo "mandatory argument ${mandatory[0]}"
echo "mandatory argument2 ${mandatory[1]}"
Basically, the idea is to consume all the options with getopt, then consume all the non-options manually, then look for more options with getopt again.