Home / Alt manpages / pod2man(1)

  • pod2man(1)
  • User command
  • linux

Build a Reliable Man Page from POD with pod2man

pod2man turns a POD file into a real section 1 manual page, ready for man to render. By the end you will have checked that page with man and made its metadata predictable. The same workflow also handles POD embedded in a Perl script.

Prerequisites: the perl package, a shell, and a text editor. This takes about 10 minutes for a small document. The examples were checked with Perl 5.38.2 on Ubuntu, where pod2man reports documentation generated for perl v5.38.2.

Checkpoint: know what pod2man produces

pod2man is a wrapper around Perl's Pod::Man module. It reads POD and writes formatted *roff source. That output is suitable for a terminal through man and nroff, or for printing through troff. It does not install a page and it does not run a Perl program.

On current non-EBCDIC systems, the default output encoding is UTF-8. This is a version-sensitive detail: versions before Pod::Man 5.00 defaulted to the older roff encoding. Check your local tool before relying on a particular default:

$ dpkg-query -W -f='${Package} ${Version}\n' perl
perl 5.38.2-3.2ubuntu0.6
$ pod2man --help | sed -n '1,8p'
Usage:
    pod2man [--center=string] [--date=string] [--encoding=encoding]
    [--errors=style] [--fixed=font] [--fixedbold=font] [--fixeditalic=font]
    [--fixedbolditalic=font] [--guesswork=rule[,rule...]] [--name=name]
    [--nourls] [--official] [--release=version] [--section=manext]

1. Create a small POD source file

POD can live in its own .pod file or between Perl's =pod and =cut directives. Start with a separate file so the input and output are easy to inspect. The =encoding utf8 line declares the input encoding; it is independent of the output encoding selected later.

=encoding utf8

=head1 NAME

weather-report - print a short weather report

=head1 SYNOPSIS

weather-report [--city NAME]

=head1 DESCRIPTION

Prints a report for the requested city. If no city is supplied, the
program uses its configured default.

=head1 OPTIONS

=over 4

=item B<--city NAME>

Select the city to report.

=back

=head1 EXIT STATUS

The program returns zero when it prints a report and non-zero when the
request cannot be completed.

=cut

Keep a real program's POD close to the command's behaviour. Names, options and exit statuses in the documentation are not checked against your code by pod2man.

2. Generate a section 1 page

Give the input and output as two positional arguments. A section 1 suffix is conventional for a user command. The output is plain text containing macros such as .TH and .SH, so it is safe to review before installing anything.

$ pod2man --section=1 weather-report.pod weather-report.1
$ sed -n '1,18p' weather-report.1
.\" Automatically generated by Pod::Man 5.38.2
.\"
.nr rF 0
.if \n(.g .if rF .nr rF 1
.de Sp
.if t .sp .5v
.if n .sp
..
.de Vb
.ft CW
.nf
.ne \$1
..
.TH WEATHER-REPORT 1 "2026-09-26" "perl v5.38.2" "User Contributed Perl Documentation"
.SH NAME

The exact generated comments and date can vary. By default the date comes from POD_MAN_DATE, SOURCE_DATE_EPOCH, the input file's modification time, or the current date for standard input. Set --date when reproducible headers matter:

$ pod2man --section=1 --date=2026-09-26 weather-report.pod weather-report.1
$ grep '^\.TH' weather-report.1
.TH WEATHER-REPORT 1 "2026-09-26" "perl v5.38.2" "User Contributed Perl Documentation"

3. Read the result as a user would

Use man with the generated file before copying it into a system directory. The leading ./ matters because it tells man to open this file rather than search the installed manual path.

$ man ./weather-report.1
WEATHER-REPORT(1)     User Contributed Perl Documentation     WEATHER-REPORT(1)

NAME
    weather-report - print a short weather report

SYNOPSIS
    weather-report [--city NAME]

If you only need a non-interactive check, render through nroff and inspect the first lines:

$ nroff -man weather-report.1 | sed -n '1,24p'
WEATHER-REPORT(1)     User Contributed Perl Documentation     WEATHER-REPORT(1)

NAME
    weather-report - print a short weather report

4. Set useful headers deliberately

The page name is normally derived from the input filename and uppercased. Use --name when the filename is generic or when reading from standard input. Use --release for the project version and the centred-header option for a project header. These values are metadata in the .TH line, not content in the NAME section.

$ pod2man --name=weather-report --section=1 \
    --release=2.4.0 --center='Acme Tools' \
    --date=2026-09-26 weather-report.pod weather-report.1
$ grep '^\.TH' weather-report.1
.TH WEATHER-REPORT 1 "2026-09-26" "2.4.0" "Acme Tools"

--official changes the default centred header to indicate a standard Perl release, unless an explicit centred header is also given. It does not make a third-party command official, so leave it out for ordinary project documentation.

5. Choose encoding and error handling consciously

Use the default UTF-8 output for modern Linux systems. --encoding=roff is a compatibility option for old formatters and has poor results for many non-ASCII characters. It does not declare the input encoding. Keep =encoding utf8 in the POD when the source contains Unicode.

The default error style is die. A malformed POD document makes pod2man abort, normally with exit status 255. That is the safest choice in a build. --errors=stderr reports formatting errors but continues where possible; --errors=pod puts a POD ERRORS section in the generated page. Do not use those recovery modes as a substitute for fixing documentation.

$ pod2man --errors=die weather-report.pod weather-report.1
$ test -s weather-report.1 && echo 'man page generated'
man page generated

6. Handle scripts and multiple files

For a Perl script containing POD, pass the script as the input. pod2man extracts its documentation and does not execute the script. Add --name if standard input is involved, because the default name for standard input is STDIN.

$ pod2man --name=weather-report --section=1 bin/weather-report bin/weather-report.1

You can supply several input and output pairs in one invocation. Each pair is processed in order:

$ pod2man \
    --section=1 bin/weather-report bin/weather-report.1 \
    --section=5 conf/weather-report.conf.pod weather-report.conf.5

For a batch build, add --verbose to print each output filename. The command exits with status 1 if any document does not produce output. With default fatal POD error handling, a syntax error can stop processing earlier pairs, so check the exit status in your build script.

Common traps and safe boundaries

  • Do not overwrite an installed page while experimenting. Write to a temporary or project-local filename, then review it.
  • Installing system-wide needs care. Installing under /usr/share/man/man1 requires elevated privileges and changes what other users see. Prefer a package build or a user-local manual path. If you deliberately copy a reviewed page there, remove that exact file to undo the change.
  • --utf8 is a no-op. It is retained for compatibility but does nothing in current pod2man because UTF-8 is already the default on this platform.
  • --lax does not validate. It is also retained for compatibility and no longer validates a manual page. Use podchecker for POD validity, then use pod2man for conversion.
  • Guesswork can surprise you. Default guesswork can format text that resembles Perl functions, variables or man-page references. Use --guesswork=none when documenting another language and want only explicit POD markup to control emphasis.

Done means

  • Encoding declared. The source declares its input encoding when it contains non-ASCII text.
  • Page generated. pod2man exits successfully and creates a non-empty .1 file.
  • Rendering checked. man ./name.1 or nroff -man name.1 shows the expected NAME, SYNOPSIS and description sections.
  • Metadata is right. The .TH line has the intended name, section, date, release and centred header.
  • Nothing installed early. No system manual directory was changed until the generated page was reviewed.