Want to move out of printer hell and into printer heaven? In this article, Marcel Gagné walks you through the basics of what really happens when you print – and gives you some clever tools to add flexibility to your printing needs.

From the author of

From the author of

Demystifying Printers and Printing

I am going to wander into frightening territory. Over the years, I have seen
several estimates regarding system administrators and printers. One figure
(which had a fairly strong argument backing up the numbers) put printer
administration at around 25 percent of a system administrator's
time. If you think printers are fun, try wandering by your tech support
people's cubicles (assuming you are not one yourself) and waiting for a
printer call to come through. You shouldn't have to wait too long. Next,
note the look on their faces when they're told it's a printer problem.

I've sort of avoided dealing with printers myself. The reason is that,
like most system administrators, I also hate dealing with printers. In this
article, I will show how you can make printer hell closer to printer
heaven. In doing this, I'll walk you through the basics of what really
happens when you print. Armed with the nuts and bolts of printing, we will then
look at some clever tools and techniques that add unprecedented flexibility to
your everyday printing needs.

Linux offers us a number of printing options. We can do text, Postscript,
local printers, as well as lpd remotes. If we want to, we can even create queues
that direct printing to our co-workers' Windows 9x printers, or
provide Windows 9x users with Linux print services (using Samba). One
printer is mostly okay, but add a few more, and you've got yourself a
real handful. What Linux does do here is provide a wide range of
options for dealing with all this diversity.

Let's go back to the beginning (well, almost) and see how this whole
thing actually works, starting with your old friend, the parallel printer.

Basic PC architectures usually have a single parallel port. A printer on that
port would actually be connected to /dev/lp0. If your PC has more than one
parallel connector (or if you added a printer card), the second and third ports
would be /dev/lp1 and /dev/lp2, respectively. Now, let's pretend you have a
basic, run-of-the-mill printer attached the first parallel port. Printing can be
as simple (or as strange) as this:

The last line, with the ctrl-L, means "send a form feed to the
printer to eject the page." Now the output of this silly job looks like
this:

This is a test.
Please ignore this print job.
There is nothing of value here.

This is what my printer configuration tool refers to as "stair stepping
of text." You may have also heard it referred to as the "staircase
effect." What happens is that my printer, a LaserJet 5L, in this case,
expects either PCL (its native printer command language) or DOS-style text. That
means carriage returns and line feeds at the end of each line, unlike Linux
files, which default to simply line feeds. In any case, this is a nice display
of the need for filters.

Let's take exactly the same lines of (non) information (minus the
echo "^L" line) and create a file called testfile. I
used pico for this, but you can use whatever editor makes you happy. If we
simply cat the file to the printer as before (with cat testfile
> /dev/lp0), the results are the same. Let's build a filter.
Here's what mine looks like:

#!/bin/bash
echo -ne \\033\&k2G
cat
echo -ne \\f

Not much to it, is there? The first echo line sends the command that
tells my LaserJet to convert Linux line feeds to carriage return followed by a
line feed, an octal escape character followed by the printer control sequence
&k2G. This is an HP code, so your printer may require a different
code. The next line simply takes the input you gave it and passes it through,
unaltered. The final line sends a form feed to eject the page. I called the file
dosfilter, moved it to /usr/local/bin, and made it executable.

# cp dosfilter /usr/local/bin
# chmod 755 dosfilter

Now let's resend the job and use the filter:

# cat testfile | /usr/local/bin/dosfilter > /dev/lp0

Now my text comes out looking normal, one line after the other, and properly
aligned. Pretty neat, but in Real LifeTM, we usually don't send
jobs to printers in this way. We create printers on the system and send jobs by
spooling them. Let's create a spooler definition called lptest. Do this by
editing /etc/printcap and adding the following information. Keep in mind that
the printcap file is quite picky about how it is laid out. That's why the
guide you received with your Linux system (assuming that you bought a nice boxed
set) tells you to use printtool, or something like it. Learning to do it the
hard way is more fun in the long run. Later, we'll use nice tools.
(Rightthe /etc/printcap file.) It looks like this:

Here's what all that means. The first line is simply a printer name. If
I send a job to a printer with the lpr command, I would specify this
queue name. The next line refers to the spool directoryin other words,
where all the information related to the current job goes. This is a directory
under the /var/spool/lpd directory (by default), but it could conceivably go
anywhere you like. /var/spool/lpd is just convention. I like to use a directory
name that is the same as the queue name (I'm funny that way).

mx refers to the maximum file size you will allow to be sent to the
printer. A zero means unlimited. The next line (:sh:\) means
"suppress header page". Since this is a physically connected device,
we have the lp option, which defines the parallel device itself
(/dev/lp0 since I have only one parallel port). The last line refers to my input
filter, the dosfilter we created earlier.

To make this all work, you need only create the spool directory
(/var/spool/lpd/lptest) and send your job to the printer.

# mkdir /var/spool/lpd/lptest
# lpr -Plptest testfile

Did you get an extra, unwanted form feed with your job? If so, modify your
dosfilter and remove (or comment out) the form feed line. Another way, if you do
not want to modify your dosfilter, would simply be to add another parameter to
the /etc/printcap definition, one that tells the printing subsystem to
"suppress formfeed." The line would look like this:

:sf:\

The options sh and sf are booleans. Their presence in the
/etc/printcap file means "true." It's up to you to decide where
these things are better located (in printcap or in a filter). For a more
complete list of printcap options, you can use man and check out the
page.

# man printcap

By default, when you send a job to the printer with the lpr command,
it uses a queue definition called lp (as opposed to lptest, or whatever name you
gave your queue). If the queue was simply named lp, the only command you need to
print is this:

# lpr printfile_name

That's why we used the long form of the command.

# lpr -Pprint_queue_name printfile_name

If you always print to a specific printer, you can add the PRINTER
environment variable to your $HOME/.bash_profile.

PRINTER=lptest ; export PRINTER

Now, after you log in, all you have to do (assuming that you want to print to
lptest) is type the first, simpler version of the print command (lpr
printfile_name).

Now let's look at printing to a remote Linux (or Unix) printer.
Let's create a printer called faraway on our current machine, called
nearlinux. The printer (the lptest we created earlier) is on another machine
called farlinux. Here's the /etc/printcap entry for nearlinux:

There are only a couple of really new things here. For starters, the
lp line that defines the physical location of my printer is gone. Now
we have an rm option, which refers to the remote hostname (the host to
which the printer is connected). The last line, :rp=lptest:, defines
the remote printer's name on that system.

The only catch here is that farlinux has to let me print. This is done by
editing the file /etc/hosts.lpd and adding the hosts or host IP addresses of the
machines that are allowed to print. My hosts.lpd file has these entries:

192.168.22.2
192.168.22.3
nearlinux

It is probably a good idea to restart your lpd daemon after making this kind
of change. One way to do this is simply to do a ps ax | grep lpd and
kill the current lpd process. The second (which may vary slightly from system to
system) is to use these commands:

# /etc/rc.d/init.d/lpd stop
# /etc/rc.d/init.d/lpd start

On some releases, you can wrap this up in one command by using
restart instead of stop followed by start. Now, from
my machine, I can send a really important file to my remote Linux machine for
printing: