Discussion:
bug#33468: A bug with yes and --help
(too old to reply)
Uko Kokņevičs
2018-11-22 18:09:35 UTC
Permalink
So I was messing around with `yes`, and after running `yes --help me` it
yes: unrecognized option '--help'
Try 'yes --help' for more information.
After a bit of more testing of this, I found the same reaction from
`whoami`. I believe this might be because both `yes` and `whoami` only
ever accept one option -- that being `--help` or `--version`, and it
says that it doesn't know what `--version` is when run with an extra
operand as well. However, `true` or `false` doesn't give a textual
$ /usr/bin/true --version
true (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Jim Meyering.
$ /usr/bin/true --version asd
$ echo $?
0
Suggested possible fixes:
1. A more general error message, e.g., `yes` only accepts one option or
none.
2. Ignore the stuff that follows the option, making `yes --help me` act
the same as `yes --help`, which kind of matches with other shell
commands in that they print help, ignore the rest of arguments and exit.
3. Ignore the option: `yes --help me` would use "--help me" as the
string to repeat.

The third one isn't really a good one, but it exists as an idea so I'm
marking it down.

----
Uko Kokņevičs (Uko Koknevics)
Pádraig Brady
2018-11-24 00:52:10 UTC
Permalink
Post by Uko Kokņevičs
So I was messing around with `yes`, and after running `yes --help me` it
yes: unrecognized option '--help'
Try 'yes --help' for more information.
After a bit of more testing of this, I found the same reaction from
`whoami`. I believe this might be because both `yes` and `whoami` only
ever accept one option -- that being `--help` or `--version`, and it
says that it doesn't know what `--version` is when run with an extra
operand as well. However, `true` or `false` doesn't give a textual
$ /usr/bin/true --version
true (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Jim Meyering.
$ /usr/bin/true --version asd
$ echo $?
0
1. A more general error message, e.g., `yes` only accepts one option or
none.
2. Ignore the stuff that follows the option, making `yes --help me` act
the same as `yes --help`, which kind of matches with other shell
commands in that they print help, ignore the rest of arguments and exit.
3. Ignore the option: `yes --help me` would use "--help me" as the
string to repeat.
The third one isn't really a good one, but it exists as an idea so I'm
marking it down.
Yes this isn't ideal
yes uses parse_long_options from gnulib which only processes
options if there is a single option specified.

I see the message got a little more confusing since:
https://git.sv.gnu.org/gitweb/?p=coreutils.git;a=commitdiff;h=v8.28-42-g5782a36
changing from unrecognized option '-', to unrecognized option '--help'
Commands that use parse_long_options() are:

cksum dd echo expr getlimits hostid hostname link logname nohup printf
sleep test tsort unlink uptime users whoami yes

thanks
Pádraig
Bernhard Voelker
2018-11-24 17:17:41 UTC
Permalink
Post by Pádraig Brady
Post by Uko Kokņevičs
So I was messing around with `yes`, and after running `yes --help me` it
yes: unrecognized option '--help'
Try 'yes --help' for more information.
After a bit of more testing of this, I found the same reaction from
`whoami`. I believe this might be because both `yes` and `whoami` only
ever accept one option -- that being `--help` or `--version`, and it
says that it doesn't know what `--version` is when run with an extra
operand as well. However, `true` or `false` doesn't give a textual
$ /usr/bin/true --version
true (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Jim Meyering.
$ /usr/bin/true --version asd
$ echo $?
0
1. A more general error message, e.g., `yes` only accepts one option or
none.
2. Ignore the stuff that follows the option, making `yes --help me` act
the same as `yes --help`, which kind of matches with other shell
commands in that they print help, ignore the rest of arguments and exit.
3. Ignore the option: `yes --help me` would use "--help me" as the
string to repeat.
The third one isn't really a good one, but it exists as an idea so I'm
marking it down.
Yes this isn't ideal
yes uses parse_long_options from gnulib which only processes
options if there is a single option specified.
https://git.sv.gnu.org/gitweb/?p=coreutils.git;a=commitdiff;h=v8.28-42-g5782a36
changing from unrecognized option '-', to unrecognized option '--help'
cksum dd echo expr getlimits hostid hostname link logname nohup printf
sleep test tsort unlink uptime users whoami yes
thanks
Pádraig
Ouch. At least for 'yes', one could argument that the program should only
care about the (GNU) long options --help and --version if they are the
only argument, and take everything else as the string(s) to be output:

$ src/yes --help | head -n2
Usage: src/yes [STRING]...
or: src/yes OPTION

$ src/yes --version | head -n2
yes (GNU coreutils) 8.30.27-806b0
Copyright (C) 2018 Free Software Foundation, Inc.

$ src/yes --help me | head -n2
src/yes --help me
src/yes --help me

$ src/yes | head -n 2
src/yes
src/yes

Patch below.
WDYT?

Have a nice day,
Berny

diff --git a/src/yes.c b/src/yes.c
index 3dd5d2f9d..b86b439a4 100644
--- a/src/yes.c
+++ b/src/yes.c
@@ -32,11 +32,6 @@

#define AUTHORS proper_name ("David MacKenzie")

-static struct option const long_options[] =
-{
- {NULL, 0, NULL, 0}
-};
-
void
usage (int status)
{
@@ -74,8 +69,6 @@ main (int argc, char **argv)

parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
usage, AUTHORS, (char const *) NULL);
- if (getopt_long (argc, argv, "+", long_options, NULL) != -1)
- usage (EXIT_FAILURE);

char **operands = argv + optind;
char **operand_lim = argv + argc;
Paul Eggert
2018-11-24 18:45:19 UTC
Permalink
Post by Bernhard Voelker
At least for 'yes', one could argument that the program should only
care about the (GNU) long options --help and --version if they are the
only argument, and take everything else as the string(s) to be output
Why is the situation different for 'yes' than for other commands? The GNU coding
standards are clear that 'yes --help foo' should act like 'yes --help'.

https://www.gnu.org/prep/standards/html_node/_002d_002dhelp.html
Bernhard Voelker
2018-11-26 08:24:32 UTC
Permalink
Post by Paul Eggert
Why is the situation different for 'yes' than for other commands? The GNU coding
standards are clear that 'yes --help foo' should act like 'yes --help'.
https://www.gnu.org/prep/standards/html_node/_002d_002dhelp.html
Thanks for the link. Indeed, 'yes' is not special in this regard - I just wanted
to get the discussion going about how the behavior should be.
Post by Paul Eggert
Post by Pádraig Brady
cksum dd echo expr getlimits hostid hostname link logname nohup printf
sleep test tsort unlink uptime users whoami yes
- dd has argument-style options,
- echo is special per se,
- expr does its own argument handling,
- getlimits is an internal program,
- nohup invokes another program.

I suggest the attached:
- defining a central 'emit_help_or_version_info' in 'system.h',
- with no change for echo, expr and getlimits,
- nohup: only scan until the 1st non-option,
- and scanning over all args for all other of the above programs.

E.g. for 'yes', all of the following successfully detecting
the --version option (and likewise for --help):

$ src/yes --version
$ src/yes hello --version
$ src/yes hello --version world
$ src/yes --version hello
$ src/yes hello --v hello -- a b

WDYT?

Have a nice day,
Berny
Eric Blake
2018-11-26 17:53:48 UTC
Permalink
Post by Bernhard Voelker
E.g. for 'yes', all of the following successfully detecting
$ src/yes --version
$ src/yes hello --version
$ src/yes hello --version world
$ src/yes --version hello
$ src/yes hello --v hello -- a b
As long as it is still possible to output the string verbatim, which it
should be with:

$ src/yes -- --version | head -1
--version
$ src/yes -- hello --version | head -1
hello --version

etc.
Post by Bernhard Voelker
WDYT?
GCS is clear that 'yes --version more' should output a help message
right away, rather than trying to go on to process the 'more' argument,
barring any strong reason that it should not ('echo' and 'test' being
two utilities that have strong reasons for being exceptions, due to
their standardized requirements). Forwarding utilities, like 'nohup' or
'env', should not reorder command line arguments, so there, it is harder
to argue whether 'env --unknown --help' should error that '--unknown' is
bad or succeed in giving help; but 'env utility --help' should NOT print
the env-specific help. Even so, with forwarding apps, GCS is clear that
'env --help --unknown' should prefer to give help rather than
complaining about --unknown. When command-line option reordering is
permitted (GCS recommends it for all non-forwarding apps), then 'yes
more --version' should output help the same as 'yes --help more', rather
than behave like non-reordering 'yes -- more --version'.

So it really boils down to an audit of which utilities are forwarding
apps (and must not reorder arguments), which utilities have special
behavior based on number of arguments (echo, test, ...), and a question
of whether unknown options should be diagnosed up front. I think your
proposal to change 'yes' makes sense, although I haven't closely thought
about the ramifications of the other utilities you are touching.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
Paul Eggert
2018-11-27 21:04:31 UTC
Permalink
I'd rather see a function than a big macro like that. Can we do it as a
function instead?

Is the idea to deprecate and/or stop using parse_long_options, since it
doesn't work the way the Gnu Coding Standards says it should? If so,
maybe it would be simpler to change parse_long_options instead. This
could involve changing the API for parse_long_options.
Bernhard Voelker
2018-11-29 08:48:34 UTC
Permalink
Post by Paul Eggert
I'd rather see a function than a big macro like that. Can we do it as a
function instead?
Is the idea to deprecate and/or stop using parse_long_options, since it
doesn't work the way the Gnu Coding Standards says it should? If so,
maybe it would be simpler to change parse_long_options instead. This
could involve changing the API for parse_long_options.
Thank you very much both for your comments.

Indeed, parse_long_options is not good enough for our purposes
in the following regards:

* it only runs if (argc == 2), i.e., it doesn't handle e.g.
$ yes --help me

* it stops at the first non-option argument, i.e., it doesn't allow
to handle the GNU standard options after an argument, e.g.
$ dd if=... --help
(The above is especially nice if one already typed a quite long dd command,
and needs to know one another option, so one could just append --help, and
then re-edit the command replacing --help by the then-known other option.)

* it does not allow to differentiate between the need to scan all
arguments vs. stopping at the first non-option argument; this is
important for programs launching other programs. E.g. nohup should
not gobble the --help option after COMMAND:
$ nohup COMMAND --help

* if a command does not allow other options, then another getopt_long call
is needed.

The attached are quite raw attempts to address this - yes, as a function
instead of a macro. ;-)

The idea is to have a function which allows only the --help or --version
option, and complaining about any other option (well, programs allowing
other options besides the GNU standard options will have their own
getopt_long loop anyway). And it allows by the SCAN_ALL parameter to
stop or not stop at the 1st non-option argument.

* [PATCH] long-options: add parse_gnu_standard_options_only
gnulib patch!

* [PATCH] all: detect --help and --version more consistently [FIXME]
FIXME: NEWS, syntax-check, tests.

Have a nice day,
Berny

Continue reading on narkive:
Loading...