1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
# Writing Man Pages with AsciiDoc
A workflow for authoring Unix man pages in AsciiDoc and installing them into
the local man database on Debian (and Debian-derived) systems.
## Why AsciiDoc
Native `roff` is terse and unforgiving. AsciiDoc is plain-text, version-control
friendly, and `asciidoctor` ships a dedicated `manpage` backend that produces
groff source indistinguishable from a hand-written page.
## Prerequisites
```sh
sudo apt install asciidoctor
```
Confirm the manpage backend is available:
```sh
asciidoctor --backend=manpage --help >/dev/null && echo OK
```
## Source File Structure
Name the source `<command>.<section>.adoc`, where the section is one of:
| Section | Contents |
|---------|--------------------------------|
| 1 | User commands |
| 5 | File formats and conventions |
| 7 | Miscellaneous / overviews |
| 8 | System administration commands |
A minimal template (`foo.1.adoc`):
```adoc
= foo(1)
Author Name <author@example.org>
:doctype: manpage
:manmanual: FOO Manual
:mansource: FOO 1.0
== NAME
foo - one-line summary of what foo does
== SYNOPSIS
*foo* [_OPTIONS_] _ARGUMENT_
== DESCRIPTION
Longer prose description of the command.
== OPTIONS
*-h*, *--help*::
Print help and exit.
*-v*, *--version*::
Print version and exit.
*-f* _FILE_, *--file*=_FILE_::
Read input from _FILE_.
== EXIT STATUS
*0*::
Success.
*1*::
General error.
== EXAMPLES
Run foo against a file:
foo -f /etc/hosts
== ENVIRONMENT
*FOO_CONFIG*::
Path to the configuration file.
== FILES
_~/.config/foo/config_::
User configuration.
== SEE ALSO
*bar*(1), *baz*(5)
== AUTHORS
Author Name <author@example.org>
== BUGS
Report bugs at https://example.org/foo/issues
```
### Mandatory elements
- **Title line** `= name(section)` sets the page name and section number.
- **`:doctype: manpage`** selects the manpage backend.
- **`NAME`, `SYNOPSIS`, `DESCRIPTION`** headers (uppercase, `==`) are required.
### Useful conventions
- `*bold*` renders as bold (commands, flags).
- `_italic_` renders as underline in terminals (variables, arguments, file
paths).
- `*cmd*(N)` for cross-references to other man pages.
- `::` after a term starts a definition list (options, environment vars).
- Indented lines in `EXAMPLES` are preformatted blocks.
## Building
Convert AsciiDoc to groff man source:
```sh
asciidoctor -b manpage foo.1.adoc
```
Output: `foo.1` in the same directory.
Preview without installing:
```sh
man -l ./foo.1
```
## Installing Locally
Debian's `man-db` reads `~/.local/share/man` automatically (it is part of the
default `MANPATH` derivation). No `manpath` edit required.
```sh
mkdir -p ~/.local/share/man/man1
cp foo.1 ~/.local/share/man/man1/
```
After installation:
```sh
man foo # works immediately
```
For `apropos` and `whatis` to find the new page, rebuild the index:
```sh
mandb -u # incremental update of the user index
```
The user-level index lives in `~/.local/share/man/index.db`; no root needed.
## System-Wide Installation (optional)
For pages that should be visible to all users:
```sh
sudo cp foo.1 /usr/local/share/man/man1/
sudo mandb
```
Use `/usr/local/share/man`, not `/usr/share/man` (the latter is reserved for
distribution-packaged pages).
## Verification
```sh
man -w foo # prints the path man would open
man -k 'one-line summary' # apropos search; requires mandb update
whatis foo
```
## Automating with Make
A minimal `Makefile`:
```makefile
PREFIX ?= $(HOME)/.local
MAN1DIR := $(PREFIX)/share/man/man1
SOURCES := $(wildcard *.1.adoc)
PAGES := $(SOURCES:.adoc=)
all: $(PAGES)
%.1: %.1.adoc
asciidoctor -b manpage $<
install: all
install -d $(MAN1DIR)
install -m 644 $(PAGES) $(MAN1DIR)/
mandb -u
clean:
rm -f $(PAGES)
.PHONY: all install clean
```
Usage: `make`, `make install`, `make clean`.
## Troubleshooting
| Symptom | Cause / Fix |
|-------------------------------------------|------------------------------------------------------------------|
| `man foo` reports "No manual entry" | File not in MANPATH; check `manpath` and `man -w foo` |
| `apropos foo` finds nothing | Run `mandb -u` |
| Page renders but options look misaligned | Ensure `::` is on the same logical line as the term it defines |
| Cross-references not linked in HTML build | Manpage backend renders them as `name(N)` text only; this is OK |
| Asciidoctor warns about missing `NAME` | The required headers must be uppercase and start with `==` |
## References
- `asciidoctor(1)`, `man(1)`, `man-pages(7)`, `mandb(8)`
- Asciidoctor manpage backend: <https://docs.asciidoctor.org/asciidoctor/latest/manpage-backend/>
- File Hierarchy Standard, ยง4.11 (manual pages)
|