Bridging the GUI to Command Line Gap: Hybrid Software

 < Day Day Up > 

Printing Tools

You already have some printing capability from the Terminal application's printing menu options and built in to the rest of your Mac OS X system. The command line, however, has its own printing facility, allowing you to direct the output of commands to a printer without having to select that output in the terminal and use the menu options to print. These command-line tools are actually fairly sophisticated, although they provide only a minimalist interface to the printing architecture. Print queuing, job-status notification, and print-job logging are all part of the standard Unix lpr printing system.

Since Mac OS X 10.2, Mac OS X has included Common Unix Printing System (CUPS) software. This package includes versions of print commands traditionally found on BSD systems as well as versions of print commands traditionally found on System V machines. Mac OS X 10.1 and earlier include only versions of BSD print commands. If you are running Mac OS X 10.1 or earlier, you do not have all the commands listed in this section. The first command listed in each subsection is the BSD-compatible command, and the one that you can find in Mac OS X 10.2 as well as earlier versions. The second command listed in each subsection is the System V compatible command and is found only in the 10.2 and more recent distributions of Mac OS X.

Sending Jobs to the Printer: lpr

The command to send a job to the printer is lpr. Although there are a number of options to lpr, the most common forms that you will probably use are

 lpr <filename> lpr -P<printer> <filename> 

The first example sends <filename> to the system's default printer. The second example sends <filename> to an alternative printer named <printer>. If your system has more than one printer available to it at the command line, the second form might be of use. Note that there is no space between the -P and <printer>. This is an example of traditional lpr syntax, which we are mentioning in case you encounter it on another system. The lpr that ships with Mac OS X 10.2 documents a space between the -P and <printer>, but the traditional syntax also works. If you are using Mac OS X 10.0 or 10.1, the lpr that ships with it documents only the traditional syntax; however, the nontraditional syntax also works. You can send multiple jobs to the printer at once, and they will be queued and printed in sequence.

The command provides no feedback other than a return to your prompt:

 brezup:ray testing $ lpr my-test brezup:ray testing $ 

Despite this, it's sent the file my-test off to be printed on my default printer. If I want to send the file to a printer other than my default printer, the -P <printername> option allows me to specify any printer configured on my system by name. Table 13.13 shows the syntax and important options for lpr.

Table 13.13. The Syntax and Important Options for lpr


Sends a job to the printer.

 lpr  [ -E ] [ -P <printer> ] [ -# <num-copies> [  -l ] [ -o        <option> ] [ -p] [ -r ] [ -C/J/T <title> ]  [ <file1> <file2> ... ] 

lpr submits files for printing. Files named on the command line are sent to the specified printer (or the default system printer if none is specified). If no files are listed on the command line, lpr reads the print file from the standard input.

-P <printer>

Specifies <printer> as the printer. Otherwise, the site's default printer is used.

-# <num-copies>

Sets the number of copies to print from 1 to 100.


Removes the named print files after printing them.

-T <title>

Sets the job name.

The other command that you can use to send a job to the printer is lp. The syntax that you will most commonly use is similar to that of lpr, but supports a number of additional options:

 lp <filename> lp -d <printer> <filename> 

Here is a sample of the command in use:

 brezup:ray testing $ lp term-window-1.tiff request id is HP_Color_LaserJet_4550-4 (1 file(s)) 

Notice that the command responds by providing the job number, HP_Color_LaserJet_4550-4, in this case. The job number consists of the printer name and a number.

Table 13.14 shows the syntax and important options for lp.

Table 13.14. The Syntax and Important Options for lp


Sends a job to the printer.

lp [ -E ] [ -c ] [ -d <printer> ] [ -h <hostname> ] [ -m ] [-n <num-copies>] [ -o <option> ] [ -q <priority> ] [ -s ] [-w] [ -t <title> ] [ -H <handling> ] [ -P <page-list> ] [ <file1> <file2> ... ]

lp [ -E ] [ -c ] [ -h <server> ] [ -i <job-id> ] [ -n <num-copies>] [ -o <option> ] [ -q <priority> ] [ -t <title> ] [ -H <handling> ] [ -P <page-list> ]

-d <printer>

Prints to the specified <printer>.

-h <server>

Specifies the print server hostname. The default is localhost or the value of the CUPS_SERVER environment variable.

-i <job-id>

Specifies an existing job to modify.


Sends email when the job is completed.

-n <num-copies>

Sets the number of copies to print from 1 to 100.

-t <title>

Sets the job name.

-H <handling>

Specifies when the job should be printed. A value of immediate prints the file immediately, a value of hold holds the job indefinitely, and a time value (HH:MM) holds the job until the specified time. Use a value of resume with the -i option to resume a held job.

-P <page-list>

Specifies which pages to print in the document. The list can contain a list of numbers and ranges (#-#) separated by commas (for example, 1,3-5,16).

Checking the Print Queue: lpq

Because lpr provides no feedback other than a return to your prompt, you might sometimes find it useful to check the print queue to check on the status of your print job. The lpq command displays the print queue:

 brezup:ray testing $ lpq HP_Color_LaserJet_4550 is ready and printing Rank    Owner   Job     File(s)                         Total Size active  ray     4       term-window-1.tiff              921600 bytes 

This actually provides quite a bit of information. From the HP_Color_LaserJet_4550 line you get the printer's name. You might see anything here, depending on how the printer has been named. For example, you might even see location and printer model number.

The output displays each print job on one line. In this example, there is only one print job. The line describing the print job includes a print job number and the filename, size, and owner. If multiple jobs were queued on the printer, however, each would be listed here, along with the job owner, making it convenient to track down who's hogging all the printer time!

Table 13.15 is the command documentation table for lpq.

Table 13.15. The Command Documentation Table for lpq


Displays the queue of print jobs.

lpq [ -E ] [ -P <printer> ] [ -a ] [ -l ] [ +<interval> ]


Forces encryption when connecting to the server.

-P <printer>

Specifies <printer> as the printer. Otherwise, the site's default printer is used.


Displays the queues for all printers.


Displays the queue information in long format. Includes the name of the host from which the job originated.


Displays a continuous report of the jobs in the queue once every <interval> seconds until the queue is empty.

The other command that you can use to check the print queue is lpstat:

 brezup:ray testing $ lpstat HP_Color_LaserJet_4550-4         ray         1080320   Wed Jan  5 22:36:32 2005 

The output of lpstat is similar to that of lpq. It includes the job number, owner, file size, and date.

Table 13.16 shows the syntax and important options for lpstat.

Table 13.16. Command Documentation Table for lpstat


Prints CUPS status information.

lpstat [ -E ] [ -h <server> ] [ -l ] [-W <which-jobs>] [-a [<printer(s)>]] [-c [<class(es)>]] [ -d ] [-o [<printer(s)>]] [ -p [<printer(s)>]] [ -r ] [ -R ] [ -s ] [ -t ] [ -u [<user(s)>]] [ -v [<printer(s)>]]

-a [<printer(s)>]

Shows the accepting state of printer queues. If no printers are specified, all printers are listed.


Shows the current default destination.

-h <server>

Specifies the CUPS server to communicate with.


Shows a long listing of printers, classes, or jobs.

-o [<printer(s)>]

Shows the jobs queue on the specified destinations. If no destinations are specified, all jobs are shown.

-p [<printer(s)>]

Shows the printers and whether they are enabled for printing. If no printers are specified, all printers are listed.


Shows whether the CUPS server is running.


Shows the ranking of print jobs.


Shows a status summary, including the default destination, a list of classes and their member printers, and a list of printers and their associated -d, -c, and -p options.


Shows all status information. This is equivalent to using the -r, -d, -c, -d, -v, -a, -p, and -o options.

-u [<user(s)>]

Shows a list of print jobs queued by the specified users. If no users are specified, lists the jobs queued by the current user.

-v [<printer(s)>]

Shows the printers and what device they are attached to. If no printers are specified, all printers are listed.

-W [<which-jobs>]

Shows the current status of jobs that are waiting or being processed, or the completion status of jobs that have finished. <which jobs> may be completed or not-completed. This option must appear before -o for it to take effect.

Removing Printer Jobs: lprm

If you decide that you want like to remove a print job from the queue, use the lprm command. You might find it useful to use in conjunction with lpq.

Here is an example of using lprm:

 brezup:sage Documents $ lpq _192_168_1_3 is ready and printing Rank    Owner   Job     File(s)                         Total Size active  sage    27      view8.tiff                      472064 bytes 1st     sage    28      view9.tiff                      422912 bytes 2nd     sage    29      view7.tiff                      424960 bytes brezup:sage Documents $ lprm 28 brezup:sage Documents $ lpq _192_168_1_3 is ready and printing Rank    Owner   Job     File(s)                         Total Size active  sage    27      view8.tiff                      472064 bytes 1st     sage    29      view7.tiff                      424960 bytes 

In this example, we used lpq to get a print job number and then used lprm to cancel a specific job number. Because this version of lprm does not provide feedback on the job cancellation, we again used lpq to verify the job's cancellation.

Table 13.17 is the command documentation table for lprm.

Table 13.17. The Command Documentation Table for lprm


Removes print jobs from the queue.

lprm [ -E ] [ - ] [ -P <printer> ] [ <job#1> <job#2> ... ]


Forces encryption when connecting to the server.


Removes all print jobs in the queue.

-P <printer>

Specifies <printer> as the printer. Otherwise, the site's default is used.


Removes from the queue the print job specified by <job#>. The <job#> can be determined by using lpq(1).

The other command that you can use to remove a print job from the queue is cancel.

Because the lp command provides the print job name when you issue the command, you might not necessarily need to check the queue. However, the cancel command does not provide output, so you might want to use cancel in conjunction with lpstat to verify the job cancellation, as shown in the following example:

 brezup:sage Documents $ lpstat _192_168_1_3-31         sage            424960   Wed Jan  5 22:38:54 2005 _192_168_1_3-32         sage            472064   Wed Jan  5 22:39:04 2005 _192_168_1_3-33         sage            422912   Wed Jan  5 22:39:11 2005 brezup:sage Documents $ cancel _192_168_1_3-32 brezup:sage Documents $ lpstat _192_168_1_3-31         sage            424960   Wed Jan  5 22:38:54 2005 _192_168_1_3-33         sage            422912   Wed Jan  5 22:39:11 2005 

Table 13.18 is the command documentation table for cancel.

Table 13.18. The Command Documentation Table for cancel


Removes print jobs from the queue.

cancel [ -a ] [ -h <server> ] [-u <username>] [ <id> ] [ <destination> ] [ <destination-id> ]


Removes all jobs from the specified destination.

-h <server>

Specifies the print server hostname. The default is localhost or the value of the CUPS_SERVER environment variable.

-u <username>

Cancels jobs owned by <username>.

Controlling CUPS from the Command Line: lpoptions, lpadmin, lpinfo

Although not strictly part of the command-line suite of printing tools, the CUPS system includes command-line management software that provides administration and control capabilities far beyond what is currently available from either Apple's Print Center or the CUPS web interface. The most important of these, lpadmin, lpoptions, and lpinfo, allow you to create, configure, examine, and delete printers that can be accessed through the standard command-line printing interface (lpr) and through GUI applications via the Print dialog.

Configuring a CUPS Printer from the Command Line

Here we will duplicate our example of adding a serial-port-based Apple ImageWriter printer that we used in Chapter 6, "Printer, Fax, and Font Management." It's assumed that the correct PPD file has been downloaded and placed in /usr/share/cups/model/, and that the foomatic-rip filter is installed in /usr/libexec/cups/filter/. The file type dummy back end shouldn't be needed, but it shouldn't hurt anything by being present either. (It's necessary for the GUI interface because it generates the list of valid device URIs from the output from the collection of backend scripts. If there isn't a file script, the GUI doesn't know that it can do file printing. But the CUPS printing system knows about file output innately, so the command-line tools simply believe whatever you tell them and don't look in the backend directory to determine what's available.)


To better understand some of the command-line options, look back to Chapter 6 for more in-depth explanations of the concepts.

In Chapter 6, we specified the printer as printer name test; gave it a location and description; picked a connection type for it; specified the device URI; and finally selected a PPD. These are exactly the same steps we'll take here, only we aren't going to take them on five separate web pages or via dialog box entries. Instead, all this goes onto a single command line.


If you didn't do it in Chapter 5, and Apple hasn't started distributing everything necessary to use CUPS and the complete suite of Gimp-Print Ghostscript drivers, you'll need to install the ESP Ghostscript version available from

Using the -p option to specify a printer that doesn't already exist causes lpadmin to create it. Using the -D option allows the provision of a description. The -L option allows the provision of a location. The -v specification of a device URI provides both the connection type and the specific connection location information. The -m option allows you to pick a PPD from the model directory, and, finally, the -E option enables the printer for access. The command needs to be run as root.

lpadmin -p test_again -D "My ImageWriter Again" -L "Still in the Attic" -v file:/dev/tty .USA28X21P1.1 -m Imagewriter.ppd -E

It might look a bit long, but it's really no more than a compound of what we did via the GUI into a single command. After executing this command, you could check your Print Center application, and you would see that a new printer had been added and activated. It will appear in the Print Center as My ImageWriter Again and be available from the command line as printer test_again.

Writing Your Own Simple Printer Driver for CUPS

As a matter of fact, from the command line, we've got considerably more power available in configuring the printer. From the Apple Print Center interface and from the CUPS administration web pages, we have only basic options available as to how to get data to the printer. I actually had to cheat a tiny bit in constructing the Chapter 6 demonstration for how to use the Print Center and CUPS interface with my ImageWriter. My serial interface currently refuses to accept any sort of flow control, and it's much faster than my poor old ImageWriter. Because of this, on large pages and images, the end of the page gets garbled because the printer can't keep up with the data stream.

I cheated by making a small modification to the foomatic-rip Perl script to throttle the speed down to something my printer can handle. Still, this is inelegant because I might have several printers that use the foomatic-rip filter, and I won't necessarily want to throttle them all down to ImageWriter speeds. The lpadmin command-line tool, however, gives me the option of saying "chuck all that automagic stuff; I'll run my printer myself, thank you very much," and allows me to specify a driver of my own creation. This comes at the cost of me having to write code to pass my data through Ghostscript (gs) for PostScript processing, if I want that functionality, and having to handle spooling the data to the printer myself.

This isn't a particularly appealing portion of the operating system to be messing around with, but it's not that difficult either. And it means that if you have any command-line software that can be made to speak to your printer, you can use it as glue between your printer and the CUPS system. For example, although only a basic vestige of a print spooler, the following code works nicely for passing PostScript code through Ghostscript (a PostScript interpreter) to format it for my ImageWriter, and for spooling the data to the serial port slowly enough that it doesn't overrun the printer's buffer.

#!/usr/local/bin/perl use Time::HiRes qw ( time alarm sleep ); $thispid = $$; open devfile, (">"."/dev/tty.USA28X1913P1.1"); while(<>) { $infile .= $_; } $tmppsname = "/tmp/tempps".$thispid.".ps"; $tmpprnname = "/tmp/tempprint".$thispid.".prn"; open temppsfile, (">".$tmppsname); print temppsfile $infile; close temppsfile; system "/usr/local/bin/gs -q -dNOPAUSE -dBATCH -sDEVICE=iwhi -sOutputFile=$tmpprnname $tmppsname"; open tempprnfile, ("<",$tmpprnname); while(read(tempprnfile,$line,128)) { print devfile $line; $line = "; sleep(.4); } close tmpprnfile; close devfile; system "rm -f $tmppsname"; system "rm -f $tmpprnname"; exit;

If I've named it /usr/local/bin/, I can load it up as the driver for a CUPS printer named testsomemore by using the command line:

lpadmin -p testsomemore -D "Ye Olde Printer" -L "Cobweb City" -i /usr/local/bin/myspooler .pl -E

The script isn't smart enough to handle data types other than PostScript, and some data streams have sections that still overrun the buffer even with a 0.4 second sleep embedded between every 128 characters (for example, the printer can't feed 128 blank lines in 0.4 seconds), but it's a solid beginning on which you could build a driver for any printer that you know how to access through the command line. If your serial interface (or other printing interface to which your printer is connected) handles flow control, you can safely do away with the makeshift sleep command and let the printer worry about pausing the interface when it needs time to catch up.

Don't struggle too hard trying to understand what that code does right now. You'll learn everything you need to know to modify it for your purposes in Chapter 18, "Using Scripting Languages," in the section on Perl programming. For now, simply understand that it does the following:


Captures data that software hands to it through CUPS.


Writes that to a temporary file with what should be a unique name.


Uses Ghostscript (gs at the command line) to process the first temporary file into the language supported by my ImageWriter.


Writes the result of this processing into a second temporary file with a unique name.


Reads that file in, 128 bytes at a time.


Sends each 128-byte chunk to the /dev/ device associated with my serial port.


Cleans up after itself by closing connections to the open files and deleting the temporary files it has used.

This method (using -i scripts to process data) is unfortunately not entirely satisfactory for all users at this time because it appears that GUI printing does not always interact cleanly with printers specified in this fashion. The testsomemore printer created in the previous example is completely functional at the command line. Under some versions of Mac OS X, it's an apparent black hole for data printed by GUI applications. Under version 10.3 and later, it appears to work, but on versions on which it's a problem, GUI applications think that they're printing, but the printer spool never sees the data. I suspect that this is a symptom of some portion of the CUPS system being misconfigured on older versions of Mac OS X, and it deciding that the target printer does not know how to handle the data type output by the application (as in, CUPS doesn't understand that the printer can handle PostScript, and so trashes the printing job rather than passing it on to the printing script). Lack of documentation prevents a complete diagnosis and correction for 10.2 versions, but Apple seems to have corrected the problem in 10.3 and 10.4.

If you wanted to extend a script like this to handle non-PostScript data, a possible solution would be to hack on a PPD like the Imagewriter.ppd file and on the script. Duplicating the script and adding the spooling functionality from this script should be fairly simple. Because already understands how to properly convert each input data format into PostScript for output, this is an easier solution than trying to write your own processing filters around the minimal spooler we've constructed here. A more complex printing script might not be so easy to integrate. We leave the investigation of both of these solutions to the creativity of the reader, should anyone other than myself be interested in whether a 1984 ImageWriter works with a 2005 Mac Mini while using a buggy serial driver that doesn't understand flow control.

Although lpadmin is useful for creating and managing printers at the command line, lpoptions is useful for examining and setting print configurations. For example, lpoptions -d testsomemore sets the default printer for command line lp and lpr printing requests to the testsomemore printer configured in the previous example. This command does not affect the default printer for GUI printing.

Finally, lpinfo is useful for querying the CUPS system about currently installed printing devices and drivers. lpinfo -m is particularly useful for determining the correct model information to hand to the -m option of the lpadmin command.

The syntax and important options for lpadmin, lpoptions, and lpinfo are shown in Tables 13.19, 13.20, and 13.21, respectively.

Table 13.19. The Syntax and Important Options for lpadmin


Configures CUPS printers and classes.

lpadmin [ -E ] [ -h <server> ] -d <destination>

lpadmin [ -E ] [ -h <server> ] -p <printer> <option(s)>

lpadmin [ -E ] [ -h <server> ] -x <destination>

lpadmin configures printer and class queues provided by CUPS. It can also be used to set the system default printer or class.

When specified before the -d, -p, or -x options, the -E option forces encryption when connecting to the server.

The first form of the command sets the default printer or class to <destination>. Subsequent print jobs submitted via the lp(1) or lpr(1) commands use this destination unless the user specifies otherwise.

The second form of the command configures the named <printer>.

The third form of the command deletes the printer or class <destination>. Any jobs that are pending for the <destination> are removed, and any job that is currently printing is aborted.

Printer Queue Configuration Options

-c <class>

Adds the named printer to <class>. If <class> doesn't exist, it is created automatically.

-i <interface>

Sets a System V style interface script for the printer. This option cannot be specified with the -P option (PPD file) and is intended for providing support for legacy printer drivers.

-o <name>=<value>

Sets a PPD or server option for the printer. PPD options can be listed using the -l option with the lpoptions command.

-o job-k-limit=<value>

Sets the kilobyte limit for per-user quotas. The <value> is an integer number of kilobytes; one kilobyte is 1024 bytes.

-o job-page-limit=<value>

Sets the page limit for per-user quotas. The <value> is the integer number of pages that can be printed; double-sided pages are counted as two pages.

-o job-quota-period=<value>

Sets the accounting period for per-user quotas. The <value> is an integer number of seconds; 86,400 seconds are in one day.

-r <class>

Removes the named printer from <class>. If <class> becomes empty as a result, it is deleted.

-u allow:<user>,<user>

Sets user-level access control on a printer. The latter two

-u deny:<user>,<user>

forms turn user-level access control off.

-u allow:all


-u deny:none


-v <device-uri>

Sets the device-uri attribute of the printer queue. If <device-uri> is a filename, it is automatically converted to the form file:/file/name.

-D <info>

Provides a textual description of the printer.


Enables the printer and accepts jobs; this is the same as running the accept and enable programs on the printer.

-L <location>

Provides a textual location of the printer.

-P <ppd-file>

Specifies a PostScript Printer Description file to use with the printer. If specified, this option overrides the -i option (interface script).

Table 13.20. The Syntax and Important Options for lpoptions


Displays or sets printer options and defaults.

lpoptions [-h <server>] -d <destination>[/<instance>] [-o <option>=<value> -o <option>=<value>...

lpoptions [-h <server>] [-E] [-p <destination >[/<instance>]] -l

lpoptions [-h <server>] [-E] [-p <destination >[/<instance>]] -o <option>[=<value>] ... -r <option>

lpoptions [-h <server>] [-E] -x <destination >[/<instance>]

-d <destination>[/<instance>]

Sets the default printer to < destination >. If <instance> is provided, that particular instance is used. Overrides the system default printer for the current user.


Enables encryption when communicating with the CUPS server.

-h <server>

Specifies the CUPS server to talk to.


Lists the printer specific options and their current settings.

-o <option>=<value>

Specifies a new option for the named destination (available options can be seen with -l).

-p <destination >[/<instance>]

Sets the < destination > and <instance> for any options that follow.

-r <option>

Removes the specified option for the named destination.

-x <destination>/<instance>

Removes the options for the named destination and instance. This option is useful for a CUPS feature that Apple has apparently not-yet implemented: management of multiple queues with different defaults on the same printer.


If no options are specified using the -o option, the current options for the named printer are reported on the standard output.

Options set with the lpoptions command are used by the lp and lpr commands when submitting jobs.

Table 13.21. The Syntax and Important Options for lpinfo


Shows available printing devices and drivers.

lpinfo [ -E ] [ -l ] [ -m ] [ -v ]


Forces encryption when connecting to the server.


Shows a long listing of devices or drivers.


Shows the available printer drivers on the system. This option is useful for discovering what -m models are available for use with the lpadmin command.


Shows the available printer devices on the system.

     < Day Day Up > 

    Mac OS X Tiger Unleashed
    Mac OS X Tiger Unleashed
    ISBN: 0672327465
    EAN: 2147483647
    Year: 2005
    Pages: 251 © 2008-2017.
    If you may any questions please contact us: