Can Go's `flag` package print usage?

Go

Go 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZtyxView Question on Stackoverflow
Solution 1 - GonemoView Answer on Stackoverflow
Solution 2 - GoIvanView Answer on Stackoverflow
Solution 3 - Gocolm.anseoView Answer on Stackoverflow
Solution 4 - GoSergey SarbashView Answer on Stackoverflow