Handling options with optional arguments with getopts

2021-08-28 Thread hancooper
‐‐‐ Original Message ‐‐‐
On Saturday, August 28, 2021 4:49 PM, Robert Elz  wrote:

> Date:Sat, 28 Aug 2021 15:26:28 +
> From:hancooper 
>
> Message-ID:  
> 
>
>
> | 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?
>
> Not break, but the ':' case will be a waste of space, as that cannot
> happen in that case, the ':' return only happens with the leading ':'
> in the opts string (I didn't bother to quote that part of the spec last
> time, as it wasn't immediately relevant).


The reason for the code is that it would be easy to use either Vuhv:s
or :Vuhv:s without having to modify the case statements when using Vuhv:s.


> | As so
>
> That should work, the ":" case (as above) won't ever happen.
>
> There's also a whole lot of meaningless quoting that you could delete
> (shell doesn't have strings ... or perhaps that is better stated as
> everything is a string, quotes aren't needed to make something into one -
> quotes are only needed where some shell magic character appears (to literally
> match the '?' that needs to be quoted) or to protect the contents of
> an expansion from further processing.
>
> So:
>
> | local shortopts="Vuhvs"
>
> quotes there are useless.
>
> | while getopts $shortopts arg; do
>
> but (double-)quoting around $shortopts can be a good idea,
> as anything that results from an expansion is subject to
> pathname expansion and field splitting ... that's not going to
> be an issue here, as the value of shortopts is known, and
> contains nothing which would trigger pathname expansion, and
> is unlikely to result in field splitting either (depends on
> the value of IFS, so it could happen) - but always quoting
> things like that is a good idea. Greg's FAQ would tell you
> it is essential ... I don't go quite that far (just 95% of the way).
>
> | case $arg in
>
> but quotes aren't essential there, because the word in a case statement
> isn't subject to those extra expansions (it wouldn't hurt to (double-)quote
> it though, for consistency)
>
> | ("V")
>
> Those quotes are useless (all the useless quotes here are also harmless,
> so if you really like the look of them, they do no harm - but they're
> unconventional in sh code).
>
> | printf '%s\n' "Version"
>
> The \ needs quoting, one way or another, so the single quotes
> are reasonable ( %s\\n would be another way ) but the double
> quotes around Version are meaningless. [Aside: if you are going
> to add meaningless quoting, using single quotes is generally
> better, the shell doesn't need to parse the insides of a single
> quoted word nearly as much as a double quoted one, so processing
> single quoted strings is marginally faster - but probably so marginally
> that you'd never be able to measure the difference].
>
> | ("v")
> | vb="$OPTARG"
>
> That's another place (the assignment) where the quotes aren't really
> needed, as neither pathname expansion nor field splitting occur there,
> but again, for consistency, keeping them can be a good idea.
>
> | ("?")
> | printf '%s\n' "Option not recognised by shortopts"
> | printf '%s\n'pfm "Invalid option: -${OPTARG}."
> | break
> | ;;
>
> You don't need the error messages, getopts will have issued
> one already, the point of the '?' case in this scenario is
> to allow the code to clean up (which the "break" is intended
> to achieve I suspect, but that's rarely the right choice, as
> it just falls out of the while loop and continues executing
> the script ... exit is a more common thing to do there.
>
> | (*)
> | printf '%s\n' "Invoke \`getopts_test -h' for details."
> | ;;
>
> That one is missing a break (or more likely, exit) which is likely
> needed for the same reason as the previous one. But since the var
> set by getopts only ever returns one char, unquoting the ? in the
> previous pattern would allow these two cases to be combined, the '?'
> (if unquoted) would match anything not previously matched, both
> a literal '?' for the error case, but also some other option where
> the char was added to the opts string (shortopts here) but the
> case pattern to handle it was forgotten.
>
> kre





Re: Handling options with optional arguments with getopts

2021-08-28 Thread Robert Elz
Date:Sat, 28 Aug 2021 15:26:28 +
From:hancooper 
Message-ID:  



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

Not break, but the ':' case will be a waste of space, as that cannot
happen in that case, the ':' return only happens with the leading ':'
in the opts string (I didn't bother to quote that part of the spec last
time, as it wasn't immediately relevant).

  | As so

That should work, the ":" case (as above) won't ever happen.

There's also a whole lot of meaningless quoting that you could delete
(shell doesn't have strings ... or perhaps that is better stated as
everything is a string, quotes aren't needed to make something into one -
quotes are only needed where some shell magic character appears (to literally
match the '?' that needs to be quoted) or to protect the contents of
an expansion from further processing.

So:

  |  local shortopts="Vuhvs"

quotes there are useless.

  |  while getopts $shortopts arg; do

but (double-)quoting around $shortopts can be a good idea,
as anything that results from an expansion is subject to
pathname expansion and field splitting ... that's not going to
be an issue here, as the value of shortopts is known, and
contains nothing which would trigger pathname expansion, and
is unlikely to result in field splitting either (depends on
the value of IFS, so it could happen) - but always quoting
things like that is a good idea.   Greg's FAQ would tell you
it is essential ... I don't go quite that far (just 95% of the way).

  |case $arg in

but quotes aren't essential there, because the word in a case statement
isn't subject to those extra expansions (it wouldn't hurt to (double-)quote
it though, for consistency)

  |  ("V")

Those quotes are useless (all the useless quotes here are also harmless,
so if you really like the look of them, they do no harm - but they're
unconventional in sh code).

  |printf '%s\n' "Version"

The \ needs quoting, one way or another, so the single quotes
are reasonable ( %s\\n would be another way ) but the double
quotes around Version are meaningless.   [Aside: if you are going
to add meaningless quoting, using single quotes is generally
better, the shell doesn't need to parse the insides of a single
quoted word nearly as much as a double quoted one, so processing
single quoted strings is marginally faster - but probably so marginally
that you'd never be able to measure the difference].

  |  ("v")
  |vb="$OPTARG"

That's another place (the assignment) where the quotes aren't really
needed, as neither pathname expansion nor field splitting occur there,
but again, for consistency, keeping them can be a good idea.

  |  ("?")
  |printf '%s\n' "Option not recognised by shortopts"
  |printf '%s\n'pfm "Invalid option: -${OPTARG}."
  |break
  |;;

You don't need the error messages, getopts will have issued
one already, the point of the '?' case in this scenario is
to allow the code to clean up (which the "break" is intended
to achieve I suspect, but that's rarely the right choice, as
it just falls out of the while loop and continues executing
the script ... exit is a more common thing to do there.

  |  (*)
  |printf '%s\n' "Invoke \`getopts_test -h' for details."
  |;;

That one is missing a break (or more likely, exit) which is likely
needed for the same reason as the previous one.   But since the var
set by getopts only ever returns one char, unquoting the ? in the
previous pattern would allow these two cases to be combined, the '?'
(if unquoted) would match anything not previously matched, both
a literal '?' for the error case, but also some other option where
the char was added to the opts string (shortopts here) but the
case pattern to handle it was forgotten.

kre




Handling options with optional arguments with getopts

2021-08-28 Thread hancooper
‐‐‐ 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

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







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




Re: Handling options with optional arguments with getopts

2021-08-27 Thread Kenneth Irving
On Fri, Aug 27, 2021 at 11:33 AM Lawrence Velázquez  wrote:
>
> On Fri, Aug 27, 2021, at 1:20 PM, nigelberlinguer wrote:
> > ‐‐‐ Original Message ‐‐‐
> > On Friday, August 27, 2021 4:02 PM, Robert Elz  wrote:
> > > 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
>
> https://www.opengroup.org/austin/lists.html
>
> --
> vq
>

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

$  help shift
shift: shift [n]
Shift positional parameters.
Rename the positional parameters $N+1,$N+2 ... to $1,$2 ...  If N is
not given, it is assumed to be 1.
Exit Status:
Returns success unless N is negative or greater than $#.

 $  help set
set: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
Set or unset values of shell options and positional parameters
Change the value of shell attributes and positional parameters, or
display the names and values of shell variables.
 ...



-- 
Ken Irving



Re: Handling options with optional arguments with getopts

2021-08-27 Thread Robert Elz
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




Re: Handling options with optional arguments with getopts

2021-08-27 Thread Lawrence Velázquez
On Fri, Aug 27, 2021, at 1:20 PM, nigelberlinguer wrote:
> ‐‐‐ Original Message ‐‐‐
> On Friday, August 27, 2021 4:02 PM, Robert Elz  wrote:
> > 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

https://www.opengroup.org/austin/lists.html

-- 
vq



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



Re: Handling options with optional arguments with getopts

2021-08-27 Thread Robert Elz
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.

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





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.