Argument Options – Why Did ‘Argument Can Be Squished Against Option’ Prevail?

historyoptions

Inspired by the recent question Why does the specific sequence of options matter for tar command?, in which the asker learned why tar -cfv test.tar *.jpg doesn't work, I'd like to ask a followup: seriously, why not?

When a command has an option -f that requires an argument and an option -v that doesn't, this:

cmd -fv foo

can be interpreted in 2 different ways: the v is the argument for the -f option and foo is a non-option argument, or foo is the argument for the -f option and the -v option is present. The first interpretation is what POSIX getopt() does, so there are lots of commands that behave that way.

I always preferred the second interpretation. Packing all the options together (regardless of whether they take arguments) seems more useful than squishing the foo up against the -f to turn -f foo into -ffoo. But this behavior barely exists anymore. The only command I've used lately that does it is Java's jar (which has a syntax clearly inspired by that Sun version of tar which accepts tar cfv tarfile ...).

Xlib has a getopt-like function, XrmParseCommand, which allows options to be specified as either taking "separate" args or "sticky" args. But it deals with long options (-display, -geometry, etc.) so it sees -fv as just another option with no relation to either -f or -v. So it's not an example of my second interpretation.

When and why did squished args become dominant? Was it already settled before POSIX, or did the POSIX mandate decide the issue? Did the first version of POSIX even have the same specific requirement as the current version? Is there any archived discussion of the subject from ancient times?

Are there any other commands (besides tar and jar) that support or have historically supported the -fv foo = -f foo -v style of option parsing?

Best Answer

First of all, in standard getopt()-style argument processing, arguments don't have to be squished against the option they apply to, they just can be. So if -f takes an argument, both of the following are valid:

command -ffoo positional arguments
command -f foo positional arguments

What you call the "second interpretation" is in fact very, very rare. As far as I can think of right now, tar and mt are the only extant commands that works that way... and, as you mention, jar, but that's only because it emulates tar. These commands process arguments very differently from the standard getopt()-style. The options are not even preceeded by -! I can't say for sure why it was rarely used, but I would guess that it's because of the fact that it's harder to tell what options go with what arguments. For example, if b and d take arguments but a, c, and e don't, then you have this:

command abcde b-argument d-argument

...which means that while you are composing the command you have to look back at the option letter group, read it again, remember which options you specified require arguments, and write out the arguments in the same order. What about this?

command adcbe b-argument d-argument

Oops, the d option got the b-argument and vice versa. Worse, if you see:

command lmnop foo bar baz

...and you are not familiar with the command, you have no idea which arguments go with which options. foo, bar, and baz might be arguments to n, o, p (and l and m take no arguments) or foo and bar might go with, say m and p while baz is a positional parameter... or many other possible combinations.

Related Question