Printing

Compared to computers, printers are slow devices, and because they are commonly shared, it is generally undesirable for users to send jobs directly to them. Instead, most operating systems provide commands to send requests to a print daemon [2] that queues jobs for printing, and handles printer and queue management. Print commands can be handled quickly because printing is done in the background when the needed resources are available.

Printing support in Unix evolved into two camps with differing commands but equivalent functionality, as summarized in Table 4-2. Commercial Unix systems and GNU/Linux usually support both camps, whereas BSD systems offer only the Berkeley style. POSIX specifies only the lp command.

Table 4-2. Printing commands

Berkeley

System V

Purpose

lpr

lp

Send files to print queue

lprm

cancel

Remove files from print queue

lpq

lpstat

Report queue status

Here is an example of their use, first with the Berkeley style:

$ lpr -Plcb102 sample.ps                 
            Send PostScript file to print queue lcb102

$ lpq -Plcb102                           
            Ask for print queue status
lcb102 is ready and printing
Rank    Owner   Job     File(s)     Total Size
active  jones   81352   sample.ps   122888346 bytes

$ lprm -Plcb102 81352                    
            Stop the presses! Kill that huge job

and then with the System V style:

$ lp -d lcb102 sample.ps                 
            Send PostScript file to print queue lcb102
request id is lcb102-81355 (1 file(s))

$ lpstat -t lcb102                       
            Ask for print queue status
printer lcb102 now printing lcb102-81355

$ cancel lcb102-81355                    
            Whoops! Don't print that job!

lp and lpr can, of course, read input from standard input instead of from command-line files, so they are commonly used at the end of a pipeline.

System management can make a particular single queue the system default so that queue names need not be supplied when the default is acceptable. Individual users can set an environment variable, PRINTER (Berkeley) or LPDEST (System V), to select a personal default printer.

Print queue names are site-specific: a small site might just name the queue printer, and make it the default. Larger sites might pick names that reflect location, such as a building abbreviation and room number, or that identify particular printer models or capabilities, such as bw for a black-and-white printer and color for the expensive one.

Unfortunately, with modern networked intelligent printers, the lprm, cancel, lpq, and lpstat commands are much less useful than they once were: print jobs arrive quickly at the printer and appear to the printer daemon to have been printed already and are thus deleted from the print queue, even though the printer may still be holding them in memory or in a filesystem while other print jobs are still being processed. At that point, the only recourse is to use the printer's control panel to cancel an unwanted job.

Evolution of Printing Technology

Printer technology has changed a lot since Unix was first developed. The industry has moved from large impact printers and electric typewriters that formed characters by hammering a ribbon and paper against a metal character shape, to electrostatic, dot-matrix, inkjet, and laser printers that make characters from tiny dots.

Advances in microprocessors allowed the implementation inside the printer of simple command languages like Hewlett-Packard Printer Command Language (PCL) and HP Graphics Language(HPGL), and complete programming languages—notably, Adobe PostScript. Adobe Portable Document Format (PDF) is a descendant of PostScript that is more compact, but not programmable. PDF offers additional features like color transparency, digital signatures, document-access control, encryption, enhanced data compression, and page independence. That last feature allows high-performance printers to rasterize pages in parallel, and PDF viewers to quickly display any requested page.

The newest generation of devices combines printing, copying, and scanning into a single system with a disk filesystem and network access, support for multiple page-description languages and graphics file formats, and, in at least one case, GNU/Linux as the embedded operating system.

Unfortunately, Unix printing software has not adapted rapidly enough to these improvements in printing technology, and command-level support for access to many features of newer printers remains poor. Two notable software projects attempt to remedy this situation: Common UNIX Printing System[3] (CUPS), and lpr next generation[4] (LPRng). Many large Unix sites have adopted one or the other; both provide familiar Unix printing commands, but with a lot more options. Both fully support printing of PostScript and PDF files: when necessary, they use the Aladdin or GNU ghostscript interpreter to convert such files to other formats needed by less-capable printers. CUPS also supports printing of assorted graphics image file formats, and n-up printing to place several reduced page images on a single sheet.

Other Printing Software

Despite its name, the venerable pr command does not print files, but rather, filters data in preparation for printing. In the simplest case, pr produces a page header timestamped with the file's modification time, or if input is from a pipe, with the current time, followed by the filename (empty for piped input) and a page number, with a fixed number (66) of lines per page. The intent was that:

pr file(s) | lp

would print nice listings. However, that simplicity has not worked since the old mechanical printers of the 1970s were retired. Default font sizes and line spacing vary between printers, and multiple paper sizes are in common use.

Instead, you generally have to experiment with setting the output page length with the -l option, and often the page width with the -w option and a text offset with the -o option. It is also essential to add the -f option (-F on some systems) to output an ASCII formfeed control character at the start of every page header after the first, to guarantee that each header starts a new page. The reality is that you generally have to use something like this:

pr -f -l60 -o10 -w65 file(s) | lp

If you use a different printer later, you may need to change those numeric parameters. This makes it hard to use pr reliably in portable shell scripts.

There is one feature of pr that is often convenient: the -c n option requests n-column output. If you combine that with the -t option to omit the page headers, you can produce nice multicolumn listings, such as this example, which formats 26 words into five columns:

$ sed -n -e 19000,19025p /usr/dict/words | pr -c5 -t
reproach      repugnant     request       reredos       resemblant
reptile       repulsion     require       rerouted      resemble
reptilian     repulsive     requisite     rerouting     resent
republic      reputation    requisition   rescind       resentful
republican    repute        requited      rescue        reserpine
repudiate

If the column width is too small, pr silently truncates data to prevent column overlap. We can format the same 26 words into 10 (truncated) columns like this:

$ sed -n -e 19000,19025p /usr/dict/words | pr -c10 -t
reproa republ repugn reputa requir requit rerout rescue resemb resent
reptil republ repuls repute requis reredo rescin resemb resent reserp
reptil repudi repuls reques requis rerout

pr has a lot of options, and historically, there was considerable variation among Unix systems in those options, and in the output format and number of lines per page. We recommend using the version from the GNU coreutils package, since it gives a uniform interface everywhere, and more options than most other versions. Consult the manual pages for pr(1) for the details.

Although some PostScript printers accept plain text, many do not. Typesetting systems like TEX and troff can turn marked-up documents into PostScript and/or PDF page images. If you have just a plain text file, how do you print it? The Unix printing system invokes suitable filters to do the conversion for you, but you then do not have any control over its appearance. The answer is text-to-PostScript filters like a2ps,[5] lptops,[6] or on Sun Solaris only, mp. Use them like this:

a2ps file > file.ps                Make a PostScript listing of file
a2ps file | lp                     Print a PostScript listing of file

lptops file > file.ps              Make a PostScript listing of file
lptops file | lp                   Print a PostScript listing of file

mp file > file.ps                  Make a PostScript listing of file
mp file | lp                       Print a PostScript listing of file

All three have command-line options to choose the font, specify the typesize, supply or suppress page headers, and select multicolumn output.

BSD, IBM AIX, and Sun Solaris systems have vgrind,[7] which filters files in a variety of programming languages, turning them into troff input, with comments in italics, keywords in bold, and the current function noted in the margin; that data is then typeset and output as PostScript. A derivative called tgrind [8] does a similar job, but with more font choices, line numbering, indexing, and support for many more programming languages. tgrind produces TEX input that readily leads to PostScript and PDF output. Figure 4-1 shows a sample of its output. Both programs are easy to use for printing of typeset program listings:

$ tgrind -p hello.c                      
               Typeset and print hello.c

$ tgrind -i 1 -fn Bookman -p hello.c     
               Print the listing shown in Figure 4-1
               

$ vgrind hello.c | lp                    
               Typeset and print hello.c
tgrind typesetting of a famous C program

Figure 4-1. tgrind typesetting of a famous C program



[2] A daemon (pronounced dee-mon) is a long-running process that provides a service, such as accounting, file access, login, network connection, printing, or time of day.

[3] Available at http://www.cups.org/ and documented in a book listed in the Chapter 16.

[4] Available at http://www.lprng.org/.

Get Classic Shell Scripting now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.