Can Go's `flag` package print usage?
GoGo Problem Overview
Is it possible for me to customize Go's flag
package so that it prints a custom usage string? I have an application with current output
Usage of ./mysqlcsvdump:
-compress-file=false: whether compress connection or not
-hostname="": database host
-outdir="": where output will be stored
-password="": database password
-port=3306: database port
-single-transaction=true: whether to wrap everything in a transaction or not.
-skip-header=false: whether column header should be included or not
-user="root": database user
and would rather have something like
Usage: ./mysqlcsvdump [options] [table1 table2 ... tableN]
Parameters:
-compress-file=false: whether compress connection or not
-hostname="": database host
-outdir="": where output will be stored
-password="": database password
-port=3306: database port
-single-transaction=true: whether to wrap everything in a transaction or not.
-skip-header=false: whether column header should be included or not
-user="root": database user
Go Solutions
Solution 1 - Go
Yes, you can do that by modifying flag.Usage
:
> var Usage = func() {
> fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
>
> flag.PrintDefaults()
> }
>
> Usage prints to standard error a usage message documenting all defined
> command-line flags. The function is a variable that may be changed to
> point to a custom function.
Example use from outside of flag
:
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "This is not helpful.\n")
}
Solution 2 - Go
If you want full customisation over your usage, you need to reimplement the flag.Usage()
function by using flag.VisitAll()
to iterate through all the parsed flags. For example:
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Custom help %s:\n", os.Args[0])
flag.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(os.Stderr, " %v\n", f.Usage) // f.Name, f.Value
})
}
Solution 3 - Go
In Feb 2018, Go 1.10 updated the default destination of flag
output:
> The default Usage function now prints its first line of output to > CommandLine.Output() instead of assuming os.Stderr, so that the usage > message is properly redirected for clients using > CommandLine.SetOutput.
(see also flag.go)
So if you want to customize your flag usage, don't assume os.Stderr
, instead use something like:
flag.Usage = func() {
w := flag.CommandLine.Output() // may be os.Stderr - but not necessarily
fmt.Fprintf(w, "Usage of %s: ...custom preamble... \n", os.Args[0])
flag.PrintDefaults()
fmt.Fprintf(w, "...custom postamble ... \n")
}
Solution 4 - Go
And finally, in Go 1.16.4 we have:
// Output returns the destination for usage and error messages. os.Stderr is returned if
// output was not set or was set to nil.
func (f *FlagSet) Output() io.Writer {
if f.output == nil {
return os.Stderr
}
return f.output
}
So, by default it uses os.Stderr
, otherwise what was set to the output.