How to Use Troff to Format PDF Documents in Linux

A picture of a person's hands typing on a laptop keyboard.

Troff is a minimal yet powerful document text processor for Linux systems. It allows you to easily create print-ready documents by compiling source files from the command line. Unlike LaTeX, Troff is incredibly lightweight and is preinstalled on most Linux systems. This tutorial shows you how to use Troff to format PDF documents in Ubuntu.

What Is Troff and Why Use It

In a basic sense, Troff is a text processing program that converts code-like scripts to printable documents. Unlike word processors, Troff does not rely on the “WYSIWYG” paradigm. Instead, it requires you to use specific types of code to handle your formatting.

The default Libreoffice Writer screen.

One of the biggest advantages of this approach is simplicity. A basic install of Troff will have everything you need to create a document. Further, its lack of a graphical user interface means that you can create a document even over SSH.

A remote OpenBSD session running Troff.

Tip: learn how to forward GUI applications over SSH in Linux.

Installing Troff

Troff is often bundled by default in most Linux distributions. You can check whether you have it in your system by running its -h flag. This will display a brief list of all the flags that your Troff install accepts.

troff -h
A terminal screen running the -h flag in Troff.

There are instances where distributions do not bundle Troff by default. In that case, you can install it by looking for the “groff” package.

A terminal window running the apt info command for groff.

This is a reimplementation of Troff and Nroff programs by the GNU Project, which includes a number of new and modern features.

You can install groff in Ubuntu by using the following command:

sudo apt install groff
A terminal window showing the apt install command for groff.

Creating Your First Troff Document

Similar to source code, every Troff document is a text file that contains instructions on how to create a document. These include the page and margin width as well as letter and page spacing.

A terminal window screen showing a complex Troff macro.

This level of control allows you to manipulate the program to create any kind of document. To simplify that, the developers of Troff created “macros” that condense these commands to a simpler syntax.

install troff linux 08 ms macros manual 609x400

One of the most common macros you will use in Troff is “ms.” It will create a document in an article style. You can create an ms document by using the touch command:

touch my-first-document.ms

Since all Troff documents are text, you can open your document by using a text editor. In my case, I am using vim. Alternatively, you can use any of these text editors for Linux.

vim my-first-document.ms
A terminal window showing a new ms document.

Understanding the Troff Format

All Troff documents follow a similar structure. Every formatting command that you make needs to be in a separate line in the content that it is trying to format. As such, a typical Troff document will look something like this:

.COMMAND1
This is a piece of content in a Troff document.
 
.COMMAND2
This is a different piece of content in a Troff document.

Two of the most basic commands that you will use in ms are .TL and .PP. The former converts your text into a title and centers it in your document, while the latter formats your text to follow a paragraph-like style.

For example, the following excerpt uses both the .TL and .PP commands:

.TL
My First Troff Document
 
.PP
This is content that I want to look like a paragraph in my final document. It is not a very long content but it is my first Troff document and it is something that I am proud of. It is about three sentences long and it should wrap around the document properly.
A terminal window showing a basic Troff document.

From here, create your document by passing your file to the Troff program.

groff -ms -Tpdf ./my-first-document.ms > output.pdf
A PDF output of a basic Troff document.

Tip: if you prefer something simpler, learn how to write in MLA format in Google Docs.

Creating Bold, Italic and Underline Text

Just like a regular word processor, most Troff macros supply a number of style commands to customize your document. For ms, these are .B, .I, .UL and .BX.

  • The .B command changes the text to boldface.
  • The .I command changes the text to italics.
  • .UL and .BX are commands that draw an underline and a box around your text, respectively.

Similar to the commands above, using these in your document requires you to separate each style on its own line:

.TL
My First Troff Document
 
.PP
This is
.B
content
.R
that I want to look like a paragraph in my final document. [...]

In this example, I created a new line before the word “content” and added the .B command to change it to boldface, then created a new line and added the .R command. This allows Troff to return to its previous style.

A PDF output of a Troff document that shows a single word in boldface.

It is important to note that you always need to add the .R command when changing style. For example, the following excerpt will not terminate the .I command since Troff did not see a .R after it:

.TL
My First Troff Document
 
.PP
This is
.I
content
that I want to look like a paragraph in my final document. [...]
A PDF output of a Troff document that shows most of the body in italic face.

Creating New Document Sections

Similar to LaTeX, Troff also supports sections and hierarchy detection, so you do not need to arrange and match each header’s level when you are editing.

To create a new section in your document, use the .NH command followed by the name of your heading.

.TL
My First Troff Document
 
.NH
My First Heading
.PP
This is content that I want to look like a paragraph in my final document.
A PDF output of a Troff document with a single numbered heading.

By default, every Troff header has a level value that dictates how the program structures and displays its content on the final document. Knowing that, you can change this value to adjust the level for a heading.

For example, the following creates a level 2 heading immediately below its parent:

.TL
My First Troff Document
 
.NH
My First Heading
.NH 2
My First Subheading
.PP
This is content that I want to look like a paragraph in my final document.
A PDF output of a Troff document that shows a page with a numbered nested heading.

Aside from regular numbered headers, Troff can also create blank headers that will still follow the document’s level hierarchy.

To do this, replace .NH with the .SH command:

.TL
My First Troff Document
 
.SH
My First Heading
.SH 2
My First Subheading
.PP
This is content that I want to look like a paragraph in my final document.
A PDF output of a Troff document that shows an unnumbered nested heading.

Tip: find out how to change margins in Google Docs.

Creating Lists in Troff

The simplicity of Troff also allows you to bend its behavior to whatever you need it to be. For example, lists do not come by default on either Troff or ms macros. Despite that, you can still create a list by combining a few ms commands.

Every list in Troff consists of three parts: an indent, a bullet and the content. To create the indent, use the .RS and .RE commands. These will move the current indent level of any text inside it by four spaces.

.RS
This is my first item.
.RE
A PDF output of a Troff document that shows a simple list item.

Next, create the bullet for your list item by using .IP. This is the “indent paragraph” command that fixes your text’s left margin to a certain width.

The .IP command also allows you to set a custom bullet point and the space between it and your text. In this case, I am setting my bullet to “[1]” and will give it four spaces.

.RS
.IP [1] 4
This is my first item.
.RE
A PDF output of a Troff document that shows a single list item with a bullet point.

Now copy and paste your .IP command to create additional list items.

.RS
.IP [1] 4
This is my first item.
.IP [2] 4
This is my second item.
.IP [3] 4
This is my third item.
.RE
A PDF output of a Troff document that shows three basic list items with bullet points.

Finally, automate this process by creating a custom macro. For example, the following excerpt bounds my .IP command to .QW:

.de QW
.IP [-] 4
..
 
.RS
.QW
This is my first item.
.QW
This is my second item.
.QW
This is my third item.
.RE
A terminal window that shows the source file of a document that used macros to automate list creation.

Creating Tables with Preprocessors in Troff

One quirk of Troff is that most of its features exist as “preprocessors.” For the most part, these are binaries outside the program that work by creating “preprocessor container scripts” and convert those to low-level Troff code.

A terminal window that shows the converted Troff code from a preprocessor.

Tbl is a great example of a Troff preprocessor. It is a program that manages tables in a document. A basic Tbl container looks something like this:

.TS
allbox ;
c c c.
item1 <Tab> item2 <Tab> item3
item4 <Tab> item5 <Tab> item6
 
.TE
  • The .TS and .TE commands tells Tbl that this is an environment that it can read.
  • The second line tells the program how to format this table.
  • The third line is a space-separated field that dictates the amount of columns and their alignment in your table.
  • The fourth and fifth lines are tab-separated fields that contain the contents of your table.
A terminal window that shows the preprocessor script for Tbl.

Compiling a document with Tbl is slightly different than a regular Troff file. First, load your file:

tbl my-first-document.ms > preprocessed.ms

Next, feed the program’s output to Troff:

groff -ms -Tpdf ./preprocessed.ms > output.pdf

Lastly, automate this process by using UNIX pipes:

tbl my-first-document.ms | groff -ms -Tpdf > output.pdf
A PDF output of a Troff document that shows a basic table.

Good to know: learn more about UNIX pipes and file redirection with sed.

Frequently Asked Questions

Is it possible to use Troff in Windows?

By default, neither Troff nor Groff are officially ported to Windows. Despite that, you can still use Groff along with other GNU utilities by installing the Windows Subsystem for Linux.

Does Troff have a bibliography tracking feature?

Yes. Refer is a simple preprocessor that uses an external bibliography file to automatically track references in a Troff document. You can learn more about how it works by visiting its manual page by running man refer.

How can I fix the "missing DESC" error when compiling Troff?

This issue is most likely due to either a missing dependency in your system or a mismatched version file. To fix this, install the proper groff package from your distribution’s repository.

Image credit: Simon Hattinga Verscheure via Unsplash. All alterations and screenshots by Ramces Red.

Is this post useful?
Subscribe to our newsletter!

Our latest tutorials delivered straight to your inbox

Ramces Red
Ramces Red - Staff Writer

Ramces is a technology writer that lived with computers all his life. A prolific reader and a student of Anthropology, he is an eccentric character that writes articles about Linux and anything *nix.