bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Handling options with optional arguments with getopts


From: nigelberlinguer
Subject: Handling options with optional arguments with getopts
Date: Fri, 27 Aug 2021 17:20:39 +0000

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Friday, August 27, 2021 4:02 PM, Robert Elz <kre@munnari.OZ.AU> wrote:

>     Date:        Fri, 27 Aug 2021 15:05:52 +0000
>     From:        nigelberlinguer via Bug reports for the GNU Bourne Again 
> SHell <bug-bash@gnu.org>
>
>     Message-ID:  
> <0IgsinjPxg5VSubCxyc64u9axdDTEubUNcQFmIaPyduotl2CyQ9g71uoLtpmXL2hUph1_eHzVRnEZ7vyyHFKqqy3OlPydQXccd2CkHyzpjA=@protonmail.com>
>
>
> | I am trying to use getopts so one of the options can use
> | an optional argument.
>
> getopts is required by POSIX to:
>
> The getopts utility shall retrieve options and option-arguments
> from a list of parameters. It shall support the Utility Syntax
> Guidelines 3 to 10, inclusive, described in XBD Section 12.2
>
> XBD 12.2 guideline 7 is:
>
> Guideline 7: Option-arguments should not be optional.
>
> That is, if you want to be able to give an option arg, or not give one,
> those should be implemented as 2 separate options.

It should be noted though, that the POSIX requirement by "Guideline 7"
is not guided by actual portability in the technical sense but by a
rule written in the POSIX standard.  Perhaps there should be an update
to POSIX on what is actually portable or not

> That said, getopts also:
>
> If an option-argument is missing:
>
> If the first character of optstring is a <colon>,
>
>           the shell variable specified by name shall be set to the
>           <colon> character and the shell variable OPTARG shall be
>
>           set to the option character found.
>
>
> which means that you can do
>
> while getopts :abc:d var
> do
> case "${var}" in
> a) .... ;;
> b) .... ;;
> c) carg=${OPTARG}; .... ;;
> d) .... ;;
> :) case "${OPTARG}" in
> c) carg=Missing; .... ;;
> *) usage ... ;;
> esac
> ?) usage Bad arg "${OPTARG}" ... ;;
> esac
> done
>
> or something like that ... but beware that it only actually works
> when the option that might have an arg is last in the args given, so
> in the case above
>
> script -a -c
>
> would do what you want, but
>
> script -c -a
>
> would not, there "-a" is the arg to the -c option, not an option itself.
> There is no way (certainly no portable way) around that.
>
> kre


I have seen the following workaround, where tho options that allows an
optional argument is defined with no arguments in shortopts.

 local vb=1  sort=0

 local OPTIND OPTARG
 local shortopts="Vuhvs"
 while getopts $shortopts arg; do
   case $arg in
     ("V") printf '%s\n' "Version" ; return ;;
     ("u") printf '%s\n' "usage"   ; return ;;
     ("h") printf '%s\n' "help"    ; return ;;
     ("v")
       # Allows argument to be optional.
       # Defines option with no arguments in shortopts.
       nextarg=${!OPTIND}
       if [[ (-n "$nextarg") && ("$nextarg" != -*) ]] ; then
         OPTIND=$((OPTIND + 1))
         vb="$nextarg"
       fi
       ;;
     #.............................
     ("s") sort=1 ; shift ;;         # shifts arg by 1
     #.............................
     (?)
       pfm "Invalid option: -${OPTARG}."
       pfm "Invoke \`myfunc -h\` for details."
       break
       ;;
   esac
 done

I also wonder whether the "shift" command is used with `getopts`.  I see people 
use
the `shift` command when doing their own parsing; and when others use `getopt`.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]