Reputation: 22291
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
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