Does your CLI tool have a man page?
If you're into writing CLI tools in Go, chances are you implement a help
sub-command or a --help
flag for each one, or have the CLI framework of your choice generate help output for you.
Awesome, but what about man pages? Unless your CLI apps are made for Windows only, you'd surely want to make your CLI tools well-behaved inhabitants of the Unix ecosystem. And this means your CLI app should come with a man
page.
Luckily, there are several ways to create man pages for your Go app, including:
- Write them manually
- Use Pandoc
- Use muesli/mango
- Use cpuguy83/go-md2man
- Use Cobra
- Use lufia/godoc2man
So you need at least five excuses for not adding a man
page to your CLI project. Better write one!
1. Write them manually
Maybe this comes as a surprise, but manpages are actually plain-text files that use a fairly simple markup language.
A typical manpage is structured like this:
SOMETHING(SECTION) User Manual SOMETHING(SECTION)
NAME
SOMETHING - briefly describe SOMETHING
SYNOPSIS
formal description of invocation
DESCRIPTION
detailed multi-line description
OPTIONS
explain/list parameters and arguments
EXAMPLES
usage examples
SEE ALSO
list related objects
AUTHOR
author(s) + contact information
COPYRIGHT
copyright/license info
VERSION DATE SOMETHING(SECTION)
Other possible sections would be ENVIRONMENT, EXIT STATUS, FILES, BUGS, or HISTORY.
Every man page belongs to a numbered section. CLI tools belong to section #1. The man
command looks for matching man pages in each section in ascending order. If two man pages of the same name exist in different section, use man <section number> <name>
to open the page in the desired section.
Let's create a minimal man page for a tool called noop
. To format the page, the example uses “man macros”—short codes at the beginning of a line, starting with a dot. See man 7 man
for more information about the macros syntax.
(Side note: BSD-based Unixes like Darwin prefer the mdoc
markup language. If you run man 7 man
there, the page claims that the man macros are a “legacy” formatting language.)
Our example page uses three marcos:
.TH [name of program] [section number] [center footer] [left footer] [center header]
: This information will be shown in the header and footer of the page, respectively..SH [string]
: A section.TP
: A “hanging tag”. The first line below.TP
is indented normally, the following lines get an extra indent. Used for flag descriptions.
There are quite a few more macros available, but these three are enough to get started:
.TH "NOOP" "1" "December 08, 2024" "Noop User Manual"
.SH NAME
noop
.SH SYNOPSIS
noop [\-v] [\-a]
.SH Description
noop does nothing.
.SH OPTIONS
.TP
\-v
Verbose output.
.TP
\-a
Do absolutely nothing at all.
.SH AUTHORS
Christoph Berger.
Save the above text to a file named “noop.1” (the extension represents the section number) and pass it to the man
command:
man ./noop.1
You should then get a page similar to this one:
NOOP(1) General Commands Manual NOOP(1)
NAME
noop
SYNOPSIS
noop [-v] [-a]
Description
noop does nothing.
OPTIONS
-v Verbose output.
-a Do absolutely nothing at all.
AUTHORS
Christoph Berger.
Noop User Manual December 8, 2024 NOOP(1)
That was quite easy, wasn't it?
To “install” a man page,
- Copy it to
/usr/local/share/man/man1/
(or the appropriate section) - Ensure the copy has mode
0644
gzip
it
Two options (source: linux.org):
cp noop /usr/local/man/man1/noop.1 && chmod 0644 /usr/local/man/man1/noop.1 && gzip /usr/local/man/man1/noop.1
A shorter version, using the install
command:
gzip noop.1 && install -g 0 -o 0 -m 0644 noop.1.gz /usr/local/man/man1/
Add these steps to the installer of your choice (such as goreleaser) or your favorite build tool.
2. Use Pandoc
Pandoc converts almost any open text format to almost any other open text format. You can make use of this to write your manpage in Markdown, with a few “extras” such as the pandoc_title_block or definition_lists extensions, that you can see in action in this sample Markdown manpage:
% NOOP(1) Noop User Manual
% Christoph Berger
% December 08, 2024
# NAME
noop
# SYNOPSIS
noop [-v] [-a]
# DESCRIPTION
noop does nothing.
# OPTIONS
-v
: Verbose output.
-a
: Do absolutely nothing at all.
Run this through pandoc
and man
to get the same man page as before:
pandoc -s -t man noop.md -o noop.1 && man ./noop.1
3. Use muesli/mango
muesli/mango generates man pages from Go flags or pflags, or from CLI frameworks like Cobra, Coral, or Kong.
Mango is a package, not a command, so you can make your CLI tool generate a man page on demand (for example, during the installation process.)
4. Use cpuguy83/go-md2man
Similar to Pandoc, the go-md2man
tool converts Markdown files into manpage format. The exact Markdown format is not documented, but a peek into the raw version of
go-md2man.1.md gives a few hints.
5. Use Cobra
The Cobra CLI framework features automated man page generation based on the data you would supply to the subcommand definitions anyway.
As of this writing, the exact way of generating a man page with Cobra is not documented.
6. Use lufia/godoc2man
Do you love to kill two birds with one stone? (Not literally, please!) Then godoc2man
is the tool for you. Write the package documentation for package main
with man
-like sections, and godoc2man
turns it into a man page.
Summary
CLI tools should follow certain standards, regardless of the language they're built with. Man pages are the Linux standard of documenting CLI tools, and the above list should contain a man page generation option for every taste.
Go build awesome tools!