‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Friday, August 27, 2021 4:02 PM, Robert Elz <k...@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`.