dotlinux blog

Writing Manual Pages on Linux: A Comprehensive Guide

In the Linux ecosystem, manual pages (or "man pages") are the primary source of documentation for commands, system calls, libraries, and utilities. They provide concise, structured information that users and developers rely on daily—whether you’re a new user learning ls or a developer debugging a system call. While many users know how to read man pages with man <command>, fewer know how to write them.

This guide will demystify the process of creating professional, user-friendly man pages. We’ll cover their structure, tools to simplify writing, step-by-step creation, testing, and best practices. By the end, you’ll be able to craft man pages that rival those of core Linux utilities.

Last Updated: 2026-01

Table of Contents#

  1. Understanding Man Page Structure
  2. Tools for Writing Man Pages
  3. Step-by-Step Guide to Creating a Man Page
  4. Advanced Tips and Techniques
  5. Testing and Installing Your Man Page
  6. Common Pitfalls and How to Avoid Them
  7. Frequently Asked Questions
  8. Conclusion
  9. References

Understanding Man Page Structure#

Man pages are organized into sections and follow a standardized internal format. Familiarizing yourself with this structure is the first step to writing effective documentation.

Man Page Sections#

Linux man pages are divided into 8 numbered sections, each covering a different type of documentation:

SectionDescription
1User commands (e.g., ls, grep)
2System calls (e.g., open, fork)
3Library functions (e.g., printf, malloc)
4Device files (e.g., /dev/sda, /dev/null)
5File formats and conventions (e.g., /etc/passwd, crontab)
6Games and screensavers
7Miscellaneous (e.g., ascii, regex, man-pages)
8System administration commands (e.g., sudo, fdisk)

When referencing a man page, you can specify the section (e.g., man 5 passwd to view the file format for /etc/passwd).

Internal Structure of a Man Page#

Regardless of the section, most man pages follow a consistent structure with standard sections. Here’s a breakdown of the key components:

SectionPurpose
NAMEShort title and one-line description (e.g., ls - list directory contents).
SYNOPSISSyntax of the command/library, including options and arguments. Uses brackets [] for optional, <> for required, ... for repeats.
DESCRIPTIONDetailed explanation of functionality, use cases, and behavior.
OPTIONSList of command-line options/flags (e.g., -v, --verbose), with descriptions.
EXAMPLESPractical usage examples with explanations.
SEE ALSOLinks to related man pages, tools, or documentation.
AUTHORCreator/maintainer of the tool or man page (discouraged in man-pages project).
REPORTING BUGSInstructions for reporting issues (e.g., email, GitHub).
COPYRIGHTLicense information (e.g., MIT, GPL).

Note: The Linux man-pages project discourages the use of AUTHOR, REPORTING BUGS, and COPYRIGHT sections. For man pages contributed to that project, author information belongs in source file comments, and bug reporting details are supplied in an auto-generated colophon.

Tools for Writing Man Pages#

Traditionally, man pages are written in troff (a text-formatting language) with macros like man or mdoc. While troff is powerful, it has a steep learning curve. Modern tools simplify the process by letting you write in friendlier formats (e.g., Markdown) and converting to troff.

Traditional Tools#

  • troff + man macros: The original system. Man pages use macros like .TH (title), .SH (section header), and .PP (paragraph) to structure content. Example:

    .TH MYTOOL 1 "2024-03-15" "MyTool 1.0" "User Commands"  
    .SH NAME  
    mytool \- a simple command-line utility  
  • mdoc macros: A more structured alternative to man macros, favored by BSD systems (e.g., FreeBSD). Uses tags like Dt (document title), Sh (section), and Nm (name). Example:

    .Dd 2024-03-15  
    .Dt MYTOOL 1  
    .Os Linux  
    .Sh NAME  
    .Nm mytool  
    .Nd a simple command-line utility  

Modern Tools#

For those who prefer avoiding troff directly, these tools streamline man page creation:

  • Ronn / ruby-ronn: Write in Markdown-like syntax and convert to troff. Supports GitHub Flavored Markdown and outputs man pages or HTML. The original Ronn is unmaintained; use ruby-ronn-ng for an actively maintained fork.

    ronn mytool.ronn  # Generates mytool.1 (man page) and mytool.html  
  • Pandoc: Convert Markdown, AsciiDoc, or reStructuredText to man pages. Example:

    pandoc mytool.md -s -t man -o mytool.1  
  • help2man: Automatically generate man pages from --help and --version output of a command. Great for simple tools but limited in customization.

    help2man ./mytool -o mytool.1  
  • go-md2man: A Go-based tool that converts Markdown to roff man pages. Popular in the Go and Kubernetes ecosystems.

    go-md2man -in mytool.md -out mytool.1  
  • scdoc: A man page generator with a simple Markdown-inspired syntax, designed specifically for man pages (not HTML). Used by several Wayland projects.

    scdoc < mytool.scd > mytool.1  
  • txt2man: Converts flat ASCII text to man page format using a shell script and awk. Useful for quick, simple man pages.

    txt2man -t MYTOOL -s 1 -v "User Commands" mytool.txt > mytool.1  
  • mandoc: A modern troff processor with syntax checking and linting. Use mandoc -T lint mytool.1 to validate your man page.

Step-by-Step Guide to Creating a Man Page#

Let’s create a man page for a hypothetical tool called greet, which prints a greeting message. We’ll use traditional man macros for full control.

Step 1: Choose the Section#

greet is a user command, so we’ll use section 1.

Step 2: Create the Source File#

Man pages for section 1 end with .1 (e.g., greet.1). Start with the man macro header:

.TH GREET 1 "2024-04-05" "1.0" "User Commands"  
  • .TH: Starts the man page. Arguments: TITLE SECTION DATE VERSION MANUAL.
    • TITLE: Uppercase name of the tool (GREET).
    • SECTION: Section number (1).
    • DATE: Last updated date.
    • VERSION: Tool version (1.0).
    • MANUAL: Category (e.g., "User Commands").

Step 3: Add Core Sections#

NAME Section#

.SH NAME  
greet \- print a personalized greeting message  
  • .SH: Starts a section (section header).
  • greet \-: Name of the tool, followed by a hyphen and one-line description.

SYNOPSIS Section#

Define the command syntax. Use:

  • [] for optional arguments.
  • <> for required arguments (placeholders).
  • ... for repeating arguments.
  • | for mutually exclusive options.
.SH SYNOPSIS  
.B greet  
.RB [ \-h | \--help ]  
.RB [ \-v | \--version ]  
.RB [ \-n | \--name " " <name> ]  
.RB [ \-c | \--color ]  
  • .B: Bold text (command/options).
  • .RB: Alternate between bold and roman (for options like -h | --help).

DESCRIPTION Section#

Explain what greet does:

.SH DESCRIPTION  
Print a friendly greeting message. If no name is provided, defaults to "World".  
Use \fB\-\-color\fR to enable colored output.  
  • \fB...\fR: Inline bold (alternatively, use .B for blocks).

OPTIONS Section#

List each option with a description:

.SH OPTIONS  
.TP  
.B \-h, \-\-help  
Display this help message and exit.  
.TP  
.B \-v, \-\-version  
Display version information and exit.  
.TP  
.B \-n, \-\-name <name>  
Specify the name to greet (default: "World").  
.TP  
.B \-c, \-\-color  
Enable ANSI colored output.  
  • .TP: "Tagged paragraph" for list items (indents the tag and wraps text).

EXAMPLES Section#

Include practical examples:

.SH EXAMPLES  
.TP  
.B Greet the world:  
greet  
.RS  
Output: "Hello, World!"  
.RE  
.TP  
.B Greet Alice with color:  
greet \-\-name Alice \-c  
.RS  
Output: (colored) "Hello, Alice!"  
.RE  
  • .RS/.RE: Indent (begin/end relative shift) for example output.

SEE ALSO and AUTHOR Sections#

.SH SEE ALSO  
.BR echo (1), printf (1)  
.SH AUTHOR  
Jane Doe <[email protected]>  
  • .BR: Alternate bold and roman for cross-references (e.g., echo(1) links to the echo man page in section 1).

Step 4: Full Sample Man Page#

Here’s the complete greet.1 file:

.TH GREET 1 "2024-04-05" "1.0" "User Commands"  
.SH NAME  
greet \- print a personalized greeting message  
.SH SYNOPSIS  
.B greet  
.RB [ \-h | \--help ]  
.RB [ \-v | \--version ]  
.RB [ \-n | \--name " " <name> ]  
.RB [ \-c | \--color ]  
.SH DESCRIPTION  
Print a friendly greeting message. If no name is provided, defaults to "World".  
Use \fB\-\-color\fR to enable colored output.  
.SH OPTIONS  
.TP  
.B \-h, \-\-help  
Display this help message and exit.  
.TP  
.B \-v, \-\-version  
Display version information and exit.  
.TP  
.B \-n, \-\-name <name>  
Specify the name to greet (default: "World").  
.TP  
.B \-c, \-\-color  
Enable ANSI colored output.  
.SH EXAMPLES  
.TP  
.B Greet the world:  
greet  
.RS  
Output: "Hello, World!"  
.RE  
.TP  
.B Greet Alice with color:  
greet \-\-name Alice \-c  
.RS  
Output: (colored) "Hello, Alice!"  
.RE  
.SH SEE ALSO  
.BR echo (1), printf (1)  
.SH AUTHOR  
Jane Doe <[email protected]>  

Advanced Tips and Techniques#

Using mdoc Macros (BSD Style)#

mdoc macros are more semantic and consistent than man macros, making them ideal for complex documentation. For example, the NAME section in mdoc uses .Nm (name) and .Nd (description):

.Dd 2024-04-05  
.Dt GREET 1  
.Os Linux  
.Sh NAME  
.Nm greet  
.Nd print a personalized greeting message  
  • .Dt: Document title (replaces .TH).
  • .Os: Operating system (optional).
  • .Nm: Name of the tool.
  • .Nd: One-line description.

Including Diagrams or Tables#

Man pages rarely include images, but simple diagrams can be added with troff’s pic preprocessor. For example, a flow chart:

.SH DIAGRAM  
.PS  
box "Start"  
arrow right  
box "Check \-n"  
arrow right  
box "Print Greeting"  
.PE  

Internationalization#

Translate man pages using GNU gettext. Create a .po file for your language, then compile it to a .mo file and install it to $mandir/<lang>/man1/.

Testing and Installing Your Man Page#

Testing Locally#

View your man page without installing it:

man ./greet.1  # Open the man page from the current directory  

Check for syntax errors with mandoc:

mandoc -T lint greet.1  # Lint the man page  
man -c greet.1          # Check for troff errors  

Installing System-Wide#

  1. Copy the man page to the appropriate directory:

    sudo cp greet.1 /usr/local/share/man/man1/  # Local user (recommended)  
    # OR  
    sudo cp greet.1 /usr/share/man/man1/        # System-wide (requires root)  
  2. Update the man page database:

    sudo mandb  # Rebuilds the man page index  
  3. Verify installation:

    man greet  # Should open your new man page  

Common Pitfalls and How to Avoid Them#

  • Missing Section in .TH: Always include the section number (e.g., .TH GREET 1). Omitting it causes rendering errors.
  • Broken SYNOPSIS Syntax: Use [], <>, and | correctly. Tools like mandoc -T lint will flag invalid syntax.
  • Inconsistent Option Formatting: Use .TP for each option and keep descriptions concise. Avoid mixing -h and --help formatting.
  • Forgetting to Update mandb: After installing, run mandb to ensure the man page is indexed.
  • Ignoring Conventions: Follow standard sections (NAME, SYNOPSIS, EXAMPLES) to keep your man page intuitive.

Frequently Asked Questions#

What is the difference between man macros and mdoc macros?#

The man macros (used with groff's -man package) are the traditional and most widely used macro set for Linux man pages. They are presentation-oriented, focusing on how content looks. The mdoc macros (used with -mdoc) are a BSD-originated alternative that is more semantic and content-based, making them better suited for complex documentation. The Linux man-pages project recommends man macros for consistency.

Can I write a man page in Markdown?#

Yes. Tools like Pandoc, go-md2man, ruby-ronn-ng, and scdoc let you write in Markdown (or Markdown-like syntax) and convert to roff man page format. This is often faster than writing raw troff, though you may lose some fine-grained formatting control.

How do I add a table of contents to my man page?#

Man pages do not traditionally include a table of contents. The standard section headings (NAME, SYNOPSIS, DESCRIPTION, etc.) serve as a built-in navigation structure. Readers use the pager's search function (typically / in less) to find specific content.

What file extension should a man page have?#

The extension indicates the manual section: .1 for section 1 (user commands), .2 for section 2 (system calls), and so on. For example, greet.1 for a user command, greet.5 for a file format. Compressed man pages use extensions like .1.gz.

How do I test my man page before installing it?#

View it locally with man ./greet.1 and lint it with mandoc -T lint greet.1 to catch syntax errors. See the Testing and Installing Your Man Page section for details.

Conclusion#

Writing man pages is a critical skill for Linux developers and system administrators. While traditional troff macros may seem intimidating, modern tools like ruby-ronn-ng, Pandoc, go-md2man, and scdoc simplify the process by letting you write in Markdown. By following the structure outlined here and testing rigorously with tools like mandoc -T lint, you can create clear, user-friendly documentation that rivals core Linux utilities. Remember: a well-written man page reduces support questions and makes your tool more accessible to users.

References#