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: hancooper
Subject: Handling options with optional arguments with getopts
Date: Sat, 28 Aug 2021 15:26:28 +0000

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

>     Date:        Fri, 27 Aug 2021 17:20:39 +0000
>     From:        nigelberlinguer <nigelberlinguer@protonmail.com>
>
>     Message-ID:  
> <MXe0alzC7mwCcivJXNfR4tp7vhikdlq89AZeQHl5yLYKqiEH54YiugyWaTtN2aRkpgcWC6tjkCOCt41IrbPIgx_jMoAkfRzo3NMLvTqV_oE=@protonmail.com>
>
>
> | 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.
>
> Those guidelines serve two purposes - they indicate what should be the
> arg format for posix standard utilities, and they specify what must be
> handled for those cases where they are specified to apply (as in getopts).
>
> | Perhaps there should be an update
> | to POSIX on what is actually portable or not
>
> There are constantly updates to POSIX - but I don't see anything likely to
> change in this area. "Works in bash" is not the definition of portable.
>
> In general, what POSIX specifies (with just a few exceptions, which
> often don't matter) is what you can rely upon working - as soon as you
> start using anything not specified by POSIX, or explicitly said
> to be unspecified or undefined, then you cannot really expect the
> code (including scripts) to work on other systems, and perhaps not
> even on later versions of the system you're using.
>
> | 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"
>
> Aside from using bash private syntax (which could be mostly avoided there
> if one had the desire) that kind of use of OPTIND is certainly not portable.
> The only defined write operation on OPTIND is to set it to 1.
>
> Further, even where something like that does work, it provides no mechanism
> for the arg to the option to begin with a '-', which might not matter in
> some cases, but certainly isn't very general.
>
> | I also wonder whether the "shift" command is used with `getopts`.
>
> No. Or not inside the loop. Once the loop is finished, the code
> should usually do
>
> shift $(( ${OPTIND} - 1 ))
>
> to remove all the args that have been processed by getopts - but that's
> not always required (there are other ways to get the remaining args, if
> any, if they are needed, but doing the shift means the remaining args are 
> "$@").
>
> Altering the arg list (in any way at all) during getopts processing produces
> unspecified results.
>
> | I see people use the `shift` command when doing their own parsing;
>
> Yes, that's often the easiest way to do it for hand rolled parsing
> (it means that what you're currently examining is always $1, and so
> there's no need to write messy code to get at a variable positional param,
> which is not trivial to do portably).
>
> | and when others use `getopt`.
>
> getopt is obsolete, and has numerous failure modes. But yes, shift
> is used when using getopt (getopt is generally implemented as an
> external command, and so cannot affect the state of the shell, including
> any shell variables, getopts is always a shell builtin command).
>
> kre

Would the code break if I use shortopts="Vuhv:s" (allows getopts to issue 
errors, not in silent mode)
but also have the (":") and ("?") checks inside the case statement?

As so

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")
       vb="$OPTARG"
       ;;
     #.............................
     ("s") sort=1 ;;
     #.............................
     (":")
       printf '%s\n' "Argument not supplied"
       printf '%s\n' "-${OPTARG} requires an argument."
       break
       ;;
     ("?")
       printf '%s\n' "Option not recognised by shortopts"
       printf '%s\n'pfm "Invalid option: -${OPTARG}."
       break
       ;;
     (*)
       printf '%s\n' "Invoke \`getopts_test -h' for details."
       ;;
   esac
 done
 shift $(( OPTIND - 1 ))







reply via email to

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