How to create your own man pages

General Layout

Manual (man) pages should obey a particular layout. This isn’t strictly necessary, but will help make your man page similar to every other in your system and not confuse or surprise your users.

When you display the man page of a program, you will normally find some of all of the following sections in usual order of appearance:

NAME
The name of the program, followed by a one-line description of what the program does. This will be read by apropos, man -k and whatis. So it’s an important section that I will be detailing further below.
SYNOPSIS
This is the command syntax used by your program. Command line syntax follows certain conventions you will want to adhere to. More details below.
DESCRIPTION
This is where you describe what the program does. It can be as long as needed, but language should be concise and clear and you shouldn’t put in here any details that will be repeated in other sections.
OPTIONS
If your program uses argument options, as described in the SYNOPSIS section, this is where you list explain what each option does.
EXAMPLES
Sometimes you may feel a need for this section, so you can better illustrate some command usage, or program behavior and output.
EXIT STATUS
Describes the application various exit status. If your program behaves conventionally – exits with status 1 on error for instance – this section isn’t strictly necessary. But you may wish to detail here any other non conventional exit codes.
SEE ALSO
Sometimes your program may be closely related to other system programs. You should in that case list those program here, along with their manual section number. For instance, if your program wraps the grep command, you may wish to reference it in here. Just write the program name followed by its manual section number between parenthesis; grep (1). You shouldn’t however list here programs that aren’t common Linux applications. If your program is related to some obscure application, chances are the user reading the man page doesn’t have it installed and it doesn’t make sense to make a reference to it. Just use it for common applications that are likely installed in the user computer.
BUGS
Any known bugs in the application should be placed in here, so the user is well informed and expects them.
AUTHOR
Your name and your email address.
COPYRIGHT
Specify here any copyright information for this manual page (not the program).

These are the most common sections in man pages. Some may be absent and you will no doubt find other sections. Just try to be consistent in how you use them by following the above advise.

Remember, although we do read man pages individually, they are all part of a documentation entity knownn as Manual that is managed by programs like mandb. Each man page is in fact, a chapter of this larger “book”. So you will want for the Linux Manual to be internally consistent.

Manual Sections

The linux manual is split into eight numbered sections, organized as follows:

   1   Executable programs or shell commands
   2   System calls (functions provided by the kernel)
   3   Library calls (functions within program libraries)
   4   Special files (usually found in /dev)
   5   File formats and conventions eg /etc/passwd
   6   Games
   7   Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
   8   System administration commands (usually only for root)
   9   Kernel routines [Non standard]

Man pages file names and location

A man page file should be named according to the following format:

    <program_name>.<section>

So, for example, a man page for a normal program called ppenv would be named ppenv.1. And if it had a configuration file you could create another man page named ppenv.5 to document this configuration file syntax and usage. If ppenv was in fact a system administration command and not a regular user program, it should be named ppenv.8, instead of ppenv.1

The system stores man pages in the /usr/share/man/ directory. This directory is further divided into section directories, one per section. So a typical tree is:

/usr/share/man
├── man1
├── man2
├── man3
├── man4
├── man5
├── man6
├── man7
├── man8

User created man pages however should not be installed there!
Instead they are installed on /usr/local/man or /usr/local/share/man. On many linux distributions, the first is in fact a symlink to the second. The command manpath will list the locations in which the mandb (explained below) command will look for manual pages:

$ manpath
/usr/local/man:/usr/local/share/man:/usr/share/man

manpath reads these locations from the /etc/manpath.config configuration file.

Installing a man page

The installation process is rather simple and only requires the man page to be gziped and copied to the correct location. Then for the man command to find it, it needs to be added to man database, with the mandb command.

$ sudo cp ppenv.1 /usr/local/share/man/man1
$ sudo gzip /usr/local/share/man/man1/ppenv.1
$ sudo mandb

What you must keep in mind is that you may need to create the man1, man2, etc. directories inside of /usr/local/share/man. In Ubuntu (and as is the case with Ubuntu-MATE) those directories aren’t created for you. Usually the man directory in /usr/local/man is empty when the operating system is installed.

Also keep in mind that a man page for the manual section 1, should go to the man1 directory and not anywhere else. As is the case for all other manual sections.

Assuming all of the above was done (and the file ppenv.1 contained well formated man source code, as described in the second part of this tutorial), the manual page was successfully installed. And the command man ppenv would now display the expected man page.

How man works

When the command man ppenv is executed, what actually happens is that man runs the groff command. groff is a text formatter that reads special macros in a file and prints the formatted contents to the standard output (the screen). groff will then often pipe its standard output to a pager program for easier reading; usually the less command.

You can read man groff for a more informative explanation on how to use it, but this isn’t strictly necessary for understanding and creating man pages.

These macros that groff reads and interprets always start with a . (dot) followed by the macro name. Some macros have additional parameters, others don’t.

Example of a complete man page contents

The zcat command can be used to see the contents of any man page that has already been installed. The output is the actual source code of a man page.

Below is the man page of a bash shell script named ppenv that you can get from https://bitbucket.org/krugar/ratscripts

$ zcat /usr/local/share/man/man1/ppenv.1.gz

.\" manpage for ppenv
.\" Contact [email protected] to correct errors or typos
.TH ppenv 1 "01 August 2016" "version 1.3.1" "ppenv manpage"
.SH NAME
ppenv - print the current python environment
.SH SYNOPSIS
.B ppenv
.RI "[" OPTION "]..."
.SH DESCRIPTION
.B ppenv
prints information about the current python environment, including python
version(s), the git branch of the current directory and information on
installed packages, IPython and the the ipdb and pydb debuggers.
.PP
.B ppenv
.RI "works best with " pyenv .
It can still report information without pyenv installed, but will have limited
reporting functionality. Git information will not print if git is not installed,
and any level of reporting more verbose than the
.IB -1 " option"
will be ignored if pip is not installed on the currently active environment.
.PP
If pyenv is installed, ppenv can show all python versions that were enabled
through either the 'global', 'local' or 'shell' options of pyenv. It also
supports the pyenv virtualenv extension.
.PP
The currently active python version is always highlighted, or prefixed with an
.RB ' * '
if running ppenv with the
.IB -c " option"
or in a terminal without color support.
.PP
.RB The " (system) " "flag indicates packages that are not installed on the
currently active environment but can still be reached through the
.IR "PATH" ". Do not confuse with"
.BR 'system' ", that may be displayed on the first line of the output; That's
the system python installation, usually at
.IR /usr/bin ", that is printed by"
.BR ppenv " when pyenv is not installed, or has not activated any environment."
See below.
.SH OPTIONS
.TP
.B -1
Prints only the first line of the output, consisting of the Python environment
.RB "and git branch. " "This is the default option" .
.TP
.B -2
.RB "(implies " -1 ") Prints also the second line of the output, with"
information on IPython and the ipdb and pydb debuggers. If pip is not installed
.RB "on the current environment, it will have the same effect as " -1 .
.TP
.B -a
.RB "(implies " -2 ") Prints all information. This includes a list of installed"
packages. If pip is not installed on the current environment, it will have the
.RB "same effect as " -1 .
.TP
.B -o
.RB "(implies " -a ") Any outdated packages will be highlighted, based on
the 'pip list -o' command.
.PP
.RS
.B "Note:"
All the above options are mutually exclusive. If they are used together, only
the rightmost option will take effect.
.RE
.TP
.B -c
Forces the use of no color in the program output. This option is not necessary
.RB "on terminals without color support, since " "ppenv" " will know when it"
needs to switch to a non color output.
.TP
.B -h
Prints program usage information and exits successfully.
.TP
.B -v
Prints the program version number and exits successfully.
.SH EXAMPLES
The following will show a typical output on a directory with a git repository
with the 'develop' branch checked out.
.PP
.RS
.BR $ " pyenv shell 3.5.2 2.7.11"
.br
.BR $ " ppenv -c"
.br
python: *3.5.2 2.7.11 (shell)    git branch: develop
.RE
.PP
The following shows a pyenv python 2.7.11 installation where neither IPython or
ipdb are installed. But because they are both installed on the system
.RI "Python environment and available in the " PATH ", they still get listed as"
.RB "as being available, hence the " (system) " flag."
.PP
.RS
.BR $ " pyenv shell 2.7.11 3.5.2"
.br
.BR $ " ppenv -2c"
.br
python: *2.7.11 3.5.3 (shell)    git branch: develop
.br
ipython: yes (system)    ipdb: yes (system)    pydb: no
.RE
.PP
Changing to a virtual environment named 'soray' that has been set with
the 'local' option of pyenv, for easier switching when walking to the directory,
results in a similar output to the following.
.PP
.RS
.BR $ " pyenv shell --unset"
.br
.BR $ " cd ~/Projects/Scripts"
.br
.BR $ " ppenv -c"
.br
python: soray *3.5.2 (local virtual)    git branch: dataopers
.RE
.PP
The following shows a typical output when pyenv is not installed, or when it
doesn't have any environment activated. The currently active Python installation
is the system one. Also showing the output of git when the prompt is in a
directory outside any git repository.
.PP
.RS
.BR $ " ppenv -2c"
.br
python: system *2.7.12 (global)    git branch: n/a
.br
ipython: yes    ipdb: yes    pydb: no
.RE
.SH EXIT STATUS
If python is not installed on the system, this program will end with exit status
1.
.SH BUGS
No known bugs.
.SH AUTHOR
Mario Figueiredo ([email protected])
.SH COPYRIGHT
MIT License
.PP
Copyright (c) 2016 Mario Figueiredo
.PP
This document is part of the ppenv software.
.PP
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.PP
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

– END OF PART I

5 Likes

-- PART II

In this second and final part we will be talking a look at the syntax of a man page, which will hopefully be the final thing you need to create your own man pages with the help of the example code that was given above.

General Macros

."

The comment macro
Any text following a comment macro is not interpreted by groff.

Example:

.\" manpage for ppenv
.\" Contact [email protected] to correct errors or typos

.TH

The Title Header
Every man page should start with this macro that sets the header and footer information of a man page, and it has the following format:

.TH [name of program] [section number] [center footer] [left footer] [center header]

The options are self explanatory. But it is important to notice that despite being optional, they are a standard of a good man page and you should use them all, as exemplified below.

Example:

.TH ppenv 1 "01 August 2016" "version 1.3.1" "ppenv manpage"

.SH

The Section Header
Man pages contents are divided into section headers as it was described on the General Layout in the first part of this tutorial. These section headers (not to be confused with man section numbers) are defined with the .SH macro. And it has the following format:

.SH [section name]

Example:

.SH NAME
.SH SYNOPSIS

groff will always convert [section name] to bold and any text written below .SH macro will be indented to the right.

Two of these section headers deserve a special mention, and I will talk about them now...

.SH NAME

This section header is of special interest because it is used by commands like whatis and apropos to output information about the man page. .SH NAME should always respect the following format:

.SH NAME
<program_name> - <oneline_description>

Example:

.SH NAME
ppenv - print the current python environment

If respected, this format will allow the whatis, apropos and man -k commands to output summary information about the manual page, which is usually very helpful in order for this man page to be included in documentation search queries.

$ whatis ppenv
ppenv (1)            - print the current python environment
$ apropos environment
ppenv (1)            - print the current python environment
baudrate (3ncurses)  - curses environment query routines
check-language-support (1) - returns the list of missing packages in order to provide a complete language environment
clearenv (3)         - clear the environment
dbus-update-activation-environment (1) - update environment used for D-Bus session services
Dpkg::BuildEnv (3)   - track build environment
env (1)              - run a program in a modified environment
environ (7)          - user environment
[...]

.SH SYNOPSIS

Man pages tend to all follow a more or less strict set of conventions regarding the way a command syntax should be represented. You can see many examples for existing man pages. But keep the following conventions in mind.

  • Optional arguments should be placed between square brackets: ppenv [OPTION]
  • If more than one argument is allowed, you can place an ellipsis after the specification: ppenv [OPTION]...
  • You don't need to name arguments. Just the string 'OPTION' is enough and is the usual convention.
  • Parameters are different in that they don't start with an hyphen or double hyphen. They are called positional parameters and usually come last in the command syntax specification. Parameters must be named: ppenv [OPTION]... [DIR]
  • Naming parameters is not an art. If it is a filepath, call it PATH, if it is a directory call it DIR, if it is the name of a file, call it FILE, etc...

When in doubt try to consult other man pages and study what the author did.

Font Attributes

Fonts are controlled by the .B, .I and .R macros representing bold, italics and roman, respectively. Roman is the standard (default) format. In addition, every two of these formats can be combined to produce an output that alternates between each format on every parameter.

.R   Roman format
.B   Bold format
.I   Italics (underline on most terminals)
.RB  Alternate between Roman and Bold
.RI  Alternate between Roman and Italics
.BR  Alternate between Bold and Roman
.BI  Alternate between Bold and Italics
.IR  Alternate between Italics and Roman
.IB  Alternate between Italics and Bold

.R This is some text -> This is some text
.B This is some text -> This is some text
.I This is some text -> This is some text
.RB "This " "is " "some text" -> This is some text
.RI "This " "is " "some text" -> This is some text
.BR "This " "is " "some text" -> This is some text
.BI "This " "is " "some text" -> This is some text
.IR "This " "is " "some text" -> This is some text
.IB This is some text -> Thisissometext

Spaces are important since they are argument separators to a macro. This is why the last line above displays without any spaces; they were interpreted by groff as the .IB arguments separator and not included in the output. For spaces to be considered, arguments must be enclosed in double quotes along with any necessary spaces.

Keep in mind that in many common terminals (and this is also true of the mate-terminal), italic fonts aren't supported. Italic text will instead be rendered as underline.

Paragraphs

Paragraphs include a series of macros that control paragraph format in different ways.

.br

The new line
The .br (lowercase) macro simply inserts a new line, without any paragraph extra space.

Example:

.BR $ " pyenv shell --unset"
.br
.BR $ " cd ~/Projects/Scripts"
.br
.BR $ " ppenv -c"

.PP

The Simple Paragraph macro
Creates a new simple paragraph. Paragraphs are formatted by groff with an extra line of empty space.

Example:

.PP
Copyright (c) 2016 Mario Figueiredo
.PP
This document is part of the ppenv software.

.RS and .RE

Start/End Indent
Indents to the right all lines (or paragraphs) between .RS (start) and .RE (end) to the right.

Example:

The following will show a typical output on a directory with a git repository
with the 'develop' branch checked out.
.PP
.RS
.BR $ " pyenv shell 3.5.2 2.7.11"
.br
.BR $ " ppenv -c"
.br
python: *3.5.2 2.7.11 (shell)    git branch: develop
.RE

groff will format the above as:

The following will show a typical output on a directory with a git repository with the 'develop' branch checked out.

       $ pyenv shell 3.5.2 2.7.11
       $ ppenv -c
       python: *3.5.2 2.7.11 (shell)    git branch: develop

.IP

Indent Paragraph
.IP takes one parameter and prints it in the current location. Anything on the next line will start printing in the same line, but indented as a block to the right. This macro (and its cousin below) is usually used on the OPTIONS and FILES section header of a man page.

Example:

.SH OPTIONS
.IP -v
print more verbose information
.IP -r
enable recursion
.IP "-f FILE"
Specify the output FILE

The above will produce the following output:

OPTIONS
      -v     print more verbose information

      -r     enable recursion

      -f FILE
             Specify the output FILE

.TP

The Tag Paragraph
Similar to .IP, but allows you to format its parameter (.IP parameters are always printed in Roman).

Example:

.SH OPTIONS
.TP
.B -v
print more verbose information
.TP
.B -r
enable recursion
.TP
.BI -f " FILE"
Specify the output FILE

The above will produce the a similar output to the .IP example. However the options will be formated as bold, and the -f option will be formated as: -f FILE (bold followed by italic)

Sourcing man pages

Manual pages can be sourced from other manual pages with the .so (lowercase) macro. Similar to a link, sourcing will instead embed the target man page into the current page and interrupt the rest of the original page processing.

This can be useful if one wishes, for instance, to properly document a program or feature that can be called by different names (grep, egrep, printf, fprintf, etc).

Example:

.TH appenv 1 "01 August 2016" "version 1.3.1" "appenv manpage"
.so man1/ppenv

The above will create a man page that simply points to the ppenv man page every time someone uses the command man appenv. The actual documentation for the appenv alias will be written in the ppenv.1 man page. This is how egrep and fprintf man pages are done, for instance.

It is important to specify the section folder (in this case man1/) in the .so macro parameter.

Converting man pages

groff can also be used to convert man pages to other formats, including html, postscript, plain ascii, or pdf.
However special care must be taken on some formats and the use of the col command may be required to remove certain invisible control characters that are still printed by groff.

# correctly convert a man file to ascii in UTF-8 format
$ groff -K utf8 -mandoc -Tutf8 ppenv.1 | col -bx > ppenv.txt

-- END OF TUTORIAL

4 Likes