Bash manual says

getopts optstring name [args]

When the end of options is encountered, getopts exits with a return value greater than zero. OPTIND is set to the index of the first non-option argument and name is set to ?.

Does it mean that

  • getopts only read in options and option arguments, but not arguments which are neither options nor option arguments?

  • getopts can't work with the case where in the command line, some options are specified after some arguments which are neither options nor option arguments? In other words, does getopts require that arguments which are neither options nor option arguments be specified after all the options and option arguments?


  • Have you tried working through the tutorial you linked to earlier? It should answer your questions. – Stephen Kitt Jul 21 '17 at 13:45
  • Yes, unless I miss something. – Tim Jul 21 '17 at 13:48

Yes, getopts is the tool to parse options in the POSIX way (even in bash, the GNU shell):


cmd -abc -dxx -e yy arg -f -g

(with an optspec of :abcd:e:fg)

-f and -g are regular arguments. getopts stops at that arg.

Generally, you do:

while getopts...
shift "$((OPTIND - 1))"
echo Remaining arguments:
[ "$#" -eq 0 ] || printf ' - %s\n' "$@"

If you want to process the options the GNU way, where options are considered after non-option arguments (except when there's a -- or when POSIXLY_CORRECT is in the environment), you can use the util-linux or busybox implementation of getopt instead (with a different API). That one also supports long options. That won't be portable outside of Linux though.

You do something like:

parsed_opts=$(getopt -o abcd:e:fg -l long -- "$@") || usage
eval "set -- $parsed_opts"
for o do
  case $o in
    (-[abcfg]) echo "no-arg option: $o"; shift;;
    (--long) echo "long option"; shift;;
    (-[de]) printf '%s\n' "option $o with arg $2"; shift 2;;
    (--) shift; break;;
    (*) echo "never reached";;
echo Remaining args:
[ "$#" -eq 0 ] || printf ' - %s\n' "$@"

Note that their will be some re-ordering in that options and their arguments will be removed from the "remaining args":

$ busybox getopt -o abcd:e:fg -l long -- -a foo bar -e x baz --l
 -a -e 'x' --long -- 'foo' 'bar' 'baz'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.