user1934428
user1934428

Reputation: 22291

zparseopt : mandatory argument not removed from the options

I reduced my problem to this minimal example:

# This is script myscript
echo $ZSH_VERSION
zparseopts -D vxa:=opt_a  vx:=opt_b
echo $1

I'm calling the script with

zsh myscript -vxa xx -vx zz a

I would expect that after processing the options, $1 would output a, but I get

5.8
xx

being printed. Why is this the case?

I am aware about a problem with my script, which is that the option vx is a prefix of vxa, and when I modify the script to

zparseopts -D vxa:=opt_a  vxb:=opt_b

and call it accordingly, I indeed get the expected result (a) in the output. So, I can fix my script by just renaming the options so that neither one is a prefix of a different option.

However, I also would like to understand, why I see the xx with my original code. There is no error in the invocation (if I replace the -D by -F, I don't get an error message). I could understand it, if my original script would simply fill the wrong variable (taking vx as an abbreviation for vxa), but I don't understand, why the script silently stops parsing after consuming the -vxa option, but not even picking up the mandatory argument xx. What is going on here, and why?

Upvotes: 1

Views: 232

Answers (1)

rowboat
rowboat

Reputation: 428

Yes it's due to the overlapping names + ambiguity regarding how -vxa should be parsed vs -vx a (the issue being that both are being taken as a -vx option with option-arg a - its mandatory arg has been consumed, and the unhyphenated xx looks like a non-option so parsing stops without any error).

man zshmodules has some useful info (bold emphasis added):

In all cases, option-arguments must appear either immediately following the option in the same positional parameter or in the next one. ...

When the names of two options that take no arguments overlap, the longest one wins, so that parsing for the specs -foo -foobar (for example) is unambiguous. However, due to the aforementioned handling of option-arguments, ambiguities may arise when at least one overlapping spec takes an argument, as in -foo: -foobar. In that case, the last matching spec wins.

If the specs are swapped around so that the shorter of the overlapping names are placed before longer ones (i.e. zparseopts -D vx:=opt_b vxa:=opt_a) it should work as you expect. For example:

#!/bin/zsh -
echo $ZSH_VERSION
zparseopts -D vx:=opt_b  vxa:=opt_a
print -r -- arg:$^@ opt_a:$^opt_a opt_b:$^opt_b
$ zsh thatScript -vxa xx -vx zz a
5.9
arg:a opt_a:-vxa opt_a:xx opt_b:-vx opt_b:zz

Upvotes: 1

Related Questions