Handling options with optional arguments with getopts

2021-08-27 Thread nigelberlinguer
‐‐‐ Original Message ‐‐‐
On Friday, August 27, 2021 4:02 PM, Robert Elz  wrote:

> Date:Fri, 27 Aug 2021 15:05:52 +
> From:    nigelberlinguer via Bug reports for the GNU Bourne Again 
> SHell 
>
> 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 ,
>
>   the shell variable specified by name shall be set to the
>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`.



Handling options with optional arguments with getopts

2021-08-27 Thread nigelberlinguer
‐‐‐ Original Message ‐‐‐
On Friday, August 27, 2021 8:52 PM, Robert Elz  wrote:

> Date:Fri, 27 Aug 2021 17:20:39 +
> From:    nigelberlinguer 
>
> Message-ID:  
> 
>
>
> | 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


Thank you very much for the explanation.




Handling options with optional arguments with getopts

2021-08-27 Thread nigelberlinguer
‐‐‐ Original Message ‐‐‐
On Friday, August 27, 2021 8:52 PM, Robert Elz  wrote:

> Date:Fri, 27 Aug 2021 17:20:39 +
> From:    nigelberlinguer 
>
> Message-ID:  
> 
>
>
> | 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.


Would parsing things yourself be made portable ?

> | 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.

One can check amongst the options defined, and allow everything else.

> | 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





Handling options with optional arguments with getopts

2021-08-27 Thread nigelberlinguer via Bug reports for the GNU Bourne Again SHell
I am trying to use getopts so one of the options can use an optional argument.

Have seen many discussions online about using getopts to handle options with 
optional arguments,
But also a lot of confusing arguments against many workarounds. Could bash 
getopts have a natural
way to introduce an option with a optional argument, and have the procedure 
documented in the bash manual,
with an example, if you please.