0

Here's a toy example that shows what I mean:

while getopts "sf:e:" opt; foundOpts="${foundOpts}${opt}" ; done
echo $foundOpts

problem is that getopts isn't particularly smart when it comes to arguments. for example, ./myscript.sh -ssssf will output option requires an argument -- f. That's good.

But if someone does ./myscript.sh -ssfss by mistake, it parses that like -ss -f ss, which is NOT desirable behavior!

How can I detect this? Ideally, I'd like to force that f parameter to be defined separately, and allow -f foo or -f=foo, but not -sf=foo or -sf foo.

Is this possible without doing something hairy? I imagine I could do something with a RegEx, along the lines of match $@ against something like -[^ef[:space:]]*[ef]{1}[ =](.*), but I'm worried about false positives (that regex might not be exactly right)

Thanks!

user3534080
  • 1,201
  • 1
  • 14
  • 21
  • 1
    You can't detect this. That's how it's supposed to work. If you don't like this way of parsing options, you can't use `getopts` and have to write your own option parser. Good luck doing that in bash. – Barmar May 13 '22 at 06:30
  • What you describe as "NOT desirable behavior" is in fact the standard behavior for unix utilities. I'd recommend learning the standard conventions, rather than trying to reinvent the world to match your idea of how things should work. – Gordon Davisson May 13 '22 at 07:38
  • @Barmar that's not true at all - see the (messy) answer I've come up with. It's not as bad as I was expecting, but there's got to be an easier-to-read option – user3534080 May 13 '22 at 08:13
  • @GordonDavisson when a typo could result in you wiping data by mistake, it's better to be extra cautious – user3534080 May 13 '22 at 08:14

1 Answers1

0

Here's what I've come up with. It seems to work, but I imagine the RegEx could be simplified. And I imagine there are edge cases I've overlooked.

validOpts="sf:e:"
optsWithArgs=$(echo "$validOpts" | grep -o .: | tr -d ':\n')

# ensure that options that require (or have optional) arguments are not combined with other short options
invalidOptArgFormats=( "[^$optsWithArgs[:space:]]+[$optsWithArgs]" "[$optsWithArgs]([^ =]|[ =]$|$)" )
IFS="|" && invalidOptArgRegEx="-(${invalidOptArgFormats[*]})"
[[ "$@" =~ $invalidOptArgRegEx ]] && echo -e "An option you provided takes an argument; it is required to have its option\n    on a separate - to prevent accidentally passing an opt as an argument.\n    (You provided ${BASH_REMATCH[0]})" && exit 1
user3534080
  • 1,201
  • 1
  • 14
  • 21