go: flag: exit 0 for default -h/-help option
When the -help
or -h
flags are undefined and invoked, the flag
package handles this situation as a special case and prints a nice and helpful default help text, but exit the process with exit code 2. This proposal proposes the exit code be 0 by default and configurable for this specific case.
Emphasis: this proposal does not propose/incur any changes to programs which has -h
or -help
defined.
As a concrete example, using gofmt
, which uses the flag
package and does not have -help
or -h
defined, the behavior today is:
$ gofmt -help
usage: gofmt [flags] [path ...]
-cpuprofile string
write cpu profile to this file
<...abbreviated...>
$ echo $?
2
The proposed behavior is:
$ gofmt -help
usage: gofmt [flags] [path ...]
-cpuprofile string
write cpu profile to this file
<...abbreviated...>
$ echo $?
0
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 4
- Comments: 29 (15 by maintainers)
Commits related to this issue
- Go 1.15 changed the exit code for --help https://github.com/golang/go/issues/37533 I am Hyrum https://www.hyrumslaw.com — committed to carlmjohnson/exitcode by carlmjohnson 4 years ago
Too bad I only see this now, I tripped over it when reading the Go 1.15 release notes.
To me it seems you just changed the command-line API of all Go programs using the flag package with the default set of command-line flags in subtle ways (given that
-h
and-help
are undefined). For example, if you were using such a program in a shell script with any undefined flag (including an undefined-h
or-help
) it produced an exit code 2. Now suddenly some undefined flags produce an exit code 0.To recreate old behavior one would now have to switch to a custom flag-set with
ContinueOnError
that handlesflag.ErrHelp
as before.For me that breaks the Go 1 Compatibility Expectations. It wasn’t a security issue, unspecified behavior, a specification error, or a bug. It was clearly specified behavior of the standard library that now has been changed in subtle ways for, in my opinion, no good reason. If one wanted the new behavior before it was always possible with the means of the
flag
package.For me one of the biggest advantages of Go is that it doesn’t change all the time breaking things that used to work before. Introducing subtle changes is even worse than breaking things, because it’s so hard to detect.
Like I said, this changes the CLI API of a lot of Go programs out there in the wild. I would even go so far to say this should be flagged as a bug and be reverted for Go 1.15.1.
For me the whole point of https://golang.org/doc/go1compat is that I can just upgrade and things generally get better. Not that behavior changes.
It’s a total waste of time if I have to comb through all release notes to check for subtle library behavior changes and then change existing code to stick to old behavior. It’s a massive advantage of Go that things keep working as they did before and generally just get better and faster. There are very few modern programming languages where you can take code that was written 8 years ago and just compile and run it successfully with the latest compiler.
As I wrote in my second message it was clearly specified in the documentation of
flag
that using an undefined-h
returns anErrHelp
and that withExitOnError
that leads to anos.Exit(2)
. There is no gray area there, it clearly specified what it did.The stderr output difference for
-h
and-help
compared to other options wasn’t specified and it doesn’t affect error codes. Much less likely that anyone depends on that. I still wouldn’t change it, but rather document it.You won’t know if this breaks existing programs, it might be deeply buried in some shell script calls. And then you recompile the binary and suddenly it behaves differently.
In my opinion this sets a dangerous precedent. It also was the correct behavior in the first place: You call a binary with a non existing flag and then you get an error code.
The exit code of usage is depend on whether the “help” or “-h” is defined for the application.
argp or argparse provide “-h” or “–help” automatically. If you want to get exit code 0 with -help, you should define “-h” your self, i think.
Changes to exit codes will affect Makefiles and Docker builds, as a couple of trivial examples, whereas output on standard error won’t.
I don’t think it’s a good idea to have specific behaviors for
-h
and-help
. There are instances where-h
does not mean-help
in some command line tools, and this change can possibly modify the behavior of scripts that use command line tools built in Go.Ignoring the point above, what is the merit, or usefulness, of homogeneously returning 0 when
-h
is present? What value does it add to tool building or automation?