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 -helpusage: gofmt [flags] [path ...] -cpuprofile string write cpu profile to this file<...abbreviated...>$ echo $?2
The proposed behavior is:
$ gofmt -helpusage: 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 --helphttps://github.com/golang/go/issues/37533I am Hyrum https://www.hyrumslaw.com — committed to carlmjohnson/exitcodeby carlmjohnson4 years ago
Most upvoted comments
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 handles flag.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.
+3
I would suggest don’t upgrade to Go 1.15 unless required.
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.
Reverting this change would be a real waste of time. The trade-off is worth it in the long run. If all OSS tools could just agree on good conventions, that’s really great. Eventually all tools will standardize on more things.
It’s nice to have improvements in a general direction. As far as I can tell, this behavior can be overridden if needed in Go apps, doesn’t it?
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.
+2
It’s not obvious to me that this violates https://golang.org/doc/go1compat. As I said above, the behavior of
-h
and-help
was never really specified, and it still isn’t really specified. You’ve disregarded the fact that the standard error output is different for-h
and-help
, but I don’t see why. Why is the exit status more relevant than the standard error output? Both are program behaviors.
As I wrote in my second message it was clearly specified in the documentation of flag
that using an undefined -h
returns an ErrHelp
and that with ExitOnError
that leads to an os.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.
I agree that it’s a grey area. But the point of https://golang.org/doc/go1compat is not that we can’t change anything in the existing libraries. It’s that we won’t break existing programs. So for areas like this that seem to me to be grey, I think it’s very relevant to ask for examples of programs that break.
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.
+2
The exit code of usage is depend on whether the “help” or “-h” is defined for the application.
$ go --help 2> /dev/null$ echo $?2$ go -help 2> /dev/null$ echo $?2$ go -h 2> /dev/null$ echo $?2$ go help > /dev/null$ echo $?0
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.
+2
It’s not obvious to me that this violates https://golang.org/doc/go1compat. As I said above, the behavior of
-h
and-help
was never really specified, and it still isn’t really specified. You’ve disregarded the fact that the standard error output is different for-h
and-help
, but I don’t see why. Why is the exit status more relevant than the standard error output? Both are program behaviors.
Changes to exit codes will affect Makefiles and Docker builds, as a couple of trivial examples, whereas output on standard error won’t.
+1
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 hom*ogeneously returning 0 when -h
is present? What value does it add to tool building or automation?
+1
←go: flag: clean up error message
go: flag: it is not reasonable not to support "-flag x" for boolean flags.→