Render Roff Documents to Text with nroff
A man page looks fine in your terminal and broken in someone else's, and nroff is the tool that shows you why. It turns a small roff document into readable terminal text, lets you choose the character encoding deliberately, and lets you inspect the command it would run without actually running it. Allow about fifteen minutes. The examples use GNU nroff 1.23.0 from groff-base 1.23.0-3build2, installed on this machine.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide assumes a shell and a document written for the groff roff language. It does not need elevated privileges. It reads the source and writes formatted text to standard output unless you redirect it yourself.
1. Check the installed nroff
Confirm which executable your shell will run and record its version:
$ command -v nroff
/usr/bin/nroff
$ nroff --version
GNU nroff (groff) version 1.23.0
The version matters because nroff is a front end to groff. Whatever it can do belongs to the installed groff release, not to nroff itself. Ask for the usage summary if you need to confirm option spelling:
$ nroff --help
usage: /usr/bin/nroff [-bcCEhikpRStUVz] [-d ctext] [-d string=text] [-K fallback-encoding] [-m macro-package] [-M macro-directory] [-n page-number] [-o page-list] [-P postprocessor-argument] [-r cnumeric-expression] [-r register=numeric-expression] [-T output-device] [-w warning-category] [-W warning-category] [file ...]
Checkpoint
If command -v finds nothing, install the distribution package that supplies nroff through your normal package-management process. Do not add a random copy to PATH while diagnosing a formatting difference.
2. Render a document from standard input
Use the -man macro package for man-page style input. This example supplies a title, a name section and a description, then sends the result straight to your terminal:
$ printf '.TH DEMO 1\n.SH NAME\ndemo \\- example\n.SH DESCRIPTION\nA short test.\n' | nroff -man -Tutf8
DEMO(1) General Commands Manual DEMO(1)
NAME
demo - example
DESCRIPTION
A short test.
The terminal may receive control sequences for bold or underlined text, so what you see can differ from the plain text above. nroff formats for a typewriter-like device: it does not produce a PDF or a web page.
-manselects the installed man macro package.-Tutf8selects UTF-8 terminal output.- Standard input means no temporary source file is needed for a quick test.
3. Render an existing file
Give the source file after the options. Replace the placeholder with a real path:
$ nroff -man -Tutf8 /path/to/example.1
To save text for a review, redirect standard output to a new destination:
$ nroff -man -Tutf8 /path/to/example.1 > /path/to/example.txt
$ test -s /path/to/example.txt && echo 'formatted output is non-empty'
formatted output is non-empty
Warning
Shell redirection with > truncates an existing destination before nroff even starts. That is a state-changing action, even though nroff itself only reads the source. Write to a new filename first if the old output matters:
$ nroff -man -Tutf8 /path/to/example.1 > /path/to/example.txt.new
$ mv /path/to/example.txt.new /path/to/example.txt
If formatting fails, remove the incomplete .new file and the previous output stays exactly where it was. Do not use sudo for ordinary rendering. If the destination directory is not writable, pick one you own rather than changing permissions without a reason.
4. Choose the output device when characters matter
GNU nroff accepts ascii, latin1, utf8 and cp1047 as -T devices. On this machine, UTF-8 is a sensible default for a UTF-8 terminal:
$ printf '.TH DEMO 1\n.SH NAME\ndemo \\- example\n' | nroff -man -Tutf8
Use ASCII when the receiving terminal or log consumer cannot handle the terminal character set:
$ printf '.TH DEMO 1\n.SH NAME\ndemo \\- example\n' | nroff -man -Tascii
If you omit -T, nroff can select a device from GROFF_TYPESETTER or the locale variables, including LC_ALL, LC_CTYPE and LANG. If no valid choice turns up, it falls back to ASCII. An explicit -T overrides GROFF_TYPESETTER, which makes a script easier to review later.
5. Inspect the constructed command without running it
When output differs between environments, -V prints the groff command that nroff would construct, and does not execute it:
$ printf '.TH DEMO 1\n.SH NAME\ndemo \\- example\n' | nroff -man -Tutf8 -V
PATH=... groff -Tutf8 -mtty-char -man
Tip
The exact PATH value and spacing depend on the environment, so treat this as diagnostics rather than a command to paste blindly: it can expose environment-dependent paths. The useful checks are that the selected device and macro package are present.
For a syntax or macro warning, add the warning options supported by groff, or use -w and -W with a warning category documented by groff(1). Keep the source unchanged until you know whether the issue is the input, the macro selection or the terminal encoding.
6. Tell output suppression apart from successful formatting
The -z option suppresses formatted output while still running the formatter, which is handy for a quiet check of a source file:
$ printf '.TH DEMO 1\n.SH NAME\ndemo \\- example\n' | nroff -man -z > /tmp/nroff-check.out
$ printf 'status=%s, bytes=%s\n' "$?" "$(wc -c < /tmp/nroff-check.out)"
status=0, bytes=0
A zero status means the formatter completed successfully for this input. It does not mean a normal output file was produced: here it is deliberately empty. Remove the temporary file afterwards if you do not need it, and do not confuse -z with a dry run of every external effect in a larger document, since macro packages can invoke groff features beyond the visible text.
7. Diagnose the usual failures
Bad arguments return status 2. A successful -V, -v, --version or --help call returns status 0 without formatting the document. Otherwise nroff returns groff's own status:
$ nroff --definitely-not-an-option >/dev/null
$ printf 'status=%s\n' "$?"
status=2
File will not open. Check its path and readability without changing it:
$ ls -l /path/to/example.1
$ test -r /path/to/example.1 && echo readable
Output looks like raw roff requests. Check the document uses the macro package it expects, such as -man. Characters look damaged in a log or pager. Make -Tutf8 or -Tascii explicit and check the consumer's encoding. Pagers such as less may need their own options to display terminal control sequences correctly: nroff does not configure the pager for you.
Done means
- Version confirmed:
nroff --versionidentifies the installed GNU groff release. - Rendering works: a roff document renders through
-manto the terminal device you intended. - Output protected: saved output was written to a new path before any file was replaced.
- Command inspected:
-Vwas used to check environment-sensitive command construction when needed. - Status understood:
-zwas treated as output suppression, not proof that a normal output file exists.