From disk to paper

Tutorial – Printing in the Shell

Author(s):

A few commands and some simple shell scripts make it easier to manage your printer so that you can access print functions quickly and automate recurring tasks.

If you work with LibreOffice or an image processing program like Gimp, you don't have to look too hard for the print function. The print icon is usually located in the upper left corner of the buttonbar; alternatively, you can press Ctrl+P. In many situations, however, it would be more practical to print without the help of an application – for example, if you want to print from a script.

Complex printing commands can also be transferred as shell commands. There are instructions to fit several pages on one sheet, for duplex printing, for cover sheets to make sorting easier, or for options to change the page orientation.

Linux basically comes with two commands for controlling printers at the command line, lp and lpr. Table 1 shows some important options, while Table 2 lists some helpful variants for everyday use. For additional options and settings, check out the extensive man pages for lp [1] and lpr [2].

Table 1

Print Commands

Action

lp

lpr

Output to default printer

lp <file>

lpr <file>

Output with printer definition

lp -d <printer> <file>

lpr -P <printer> <file>

Number of copies (max. 100)

lp -n <count> [...]

lpr -# <count> [...]

Print without filter

lp -o raw [...]

lpr -o raw [...]

Pages to print

lp -P <Pages> [...]

Table 2

Print Options

Action

Input

Note

Paper size

-o media=<format>

For example, a3, a4, a5

Landscape

-o landscape

Single-sided printing

-o sides=one-sided

Duplex printing

-o sides=two-sided-long-edge

Flip on long edge

Duplex printing

-o sides=two-sided-short-edge

Flip on short edge

Fit to page

-o fit-to-page

Group multiple pages on one sheet

-o number-up=<number>

Supported values: 2, 4, 6, 9, 16

Displaying the Queue

The status of the currently pending print tasks can be displayed using the lpq or lpstat commands. If executed without any further options, both commands display the queue for the default printer. Optionally, use the -P <printer> option to specify the desired printer.

All printers and their current status can be obtained by typing lpstat -a, lpstat -o, or lpq -a (Figure 1). The lpstat -t command provides a comprehensive overview of printers, queues, and jobs.

Figure 1: There are many approaches for displaying the queued jobs.

If print jobs are available, you will see output like that shown in Figure 2. Among other things, you will find the job number with which you can manage a print job in the queue, if needed. For various actions you have to extract the print job number from the output.

Figure 2: The number appended to the printer name with a hyphen corresponds to the number of the print job.

You can use the command from Listing 1 to filter the number of the current print job from the status report and then use the number to obtain additional information about the print request, delete the associated request, or move it to another printer.

Listing 1

Print Job Number

$ lpq -al | grep job | cut -d\[ -f2 | cut -d ' ' -f2

Managing Print Jobs

To cancel a print job, type lprm <job number> or cancel <job number>. You can extract the job number from the queue display by typing lpq -a. To cancel a print job, you either have to be the owner of the print job or have appropriate administrative rights. Regardless of which printer, cancel -a deletes all the current print jobs. This is why it makes more sense to specify the printer with the option. In Figure 3, lprm is used to delete one of the existing print jobs.

Figure 3: If you send your 100-page master's thesis to the wrong printer, you can cancel the job at the command line.

If a printer fails during operation, but you do not want to interrupt the print job, you can move it to another device using lpmove – provided you have the appropriate rights. You can use this command in the form lpmove <Job number> <New printer> or for all print jobs of a printer with lpmove <Old printer> <New printer>. Figure 4 shows how to move print jobs from one printer to another.

Figure 4: If a printer unexpectedly fails, you can reroute the print jobs to a working printer.

Scripted Jobs

Together with some other shell functions, the commands presented here can be assembled to create a script that prints details about a print job and deletes it at the push of a button if necessary (Listing 2). If you want to use the routine as a function in your own shell scripts, cut the djobs () { [...] } function and paste it at the start of your own program.

Listing 2

Print Job Details

01 #!/bin/bash
02
03 djobs () {
04   clear
05   echo "Current print jobs:"
06   echo "---------------------------------------------------------------"
07   lpq -a
08   echo "---------------------------------------------------------------"
09   echo "Select print job: "
10   dj=$(lpq -al | grep job | cut -d\[ -f2 | cut -d ' ' -f2 | smenu -n10 -t1 )
11
12   echo "Selected print job: $dj"
13   lpq -a $dj
14   echo "---------------------------------------------------------------"
15   action=$(echo "Nothing cancel" | smenu -m "Select action" )
16
17   if [ "$action" = "Cancel" ]; then
18     lprm $dj
19     if [ $? -eq 0 ]; then
20       echo "Print job $dj deleted"
21     fi
22     sleep 2
23   fi
24   exit 0
25 }
26 djobs

With a little help from the smenu [3] and YAD tools, it is quite easy to implement selection dialogs. The smenu command-line tool is recommended for command-line wizards and users who need to work on a remote computer via SSH. YAD on the other hand is an option for users who prefer the comfort of the desktop environment. The program displays windows on the screen with simple instructions.

Smenu and YAD are missing from the default software selection in most distributions. But, thanks to the smenu and yad packages, the two programs can be installed quickly from the package sources.

In smenu, the -m <Title> option shows the user what they are selecting and, if necessary, why. Without further options, you would select the desired entry word by word within a line. -n <number> limits the selection lines; t1 tells smenu to display the selection line by line in a single column. Figure 5 shows the flow of the script.

Figure 5: The djobs() function from Listing 2 wraps what are often cryptic printing commands in simple dialogs.

The script from Listing 3 is recommended for a terminal session. It selects the printer for the print output, the queue display, or a queue you want to move. The example in Figure 6 lists the print jobs for a specific printer.

Listing 3

Select Printer

#!/bin/bash
prin () {
  clear
  target=$(/usr/sbin/lpc status all | grep \: | tr -d \: | smenu -n3 -c -m "Select a printer:")
  # Example: Queue output
  lpq -P$target
  exit 0
}
prin
Figure 6: The prin() function from Listing 3 lists all the available printers and outputs the print queue for the selected device.

YAD is a good choice if you are looking for a graphic alternative. Without too much programming work, you can use this tool to create simple applications based on a shell script. The example in Listing 4 shows how to select a printer and the file to be printed.

Listing 4

Select Printer and File

01 #! /bin/sh
02 prin {
03   clear
04   # Read printers
05   z=0
06   pline=""
07   for i in $(/usr/sbin/lpc status all | grep : | tr -d \: ); do
08     pline=$(echo $pline$i!)
09   done
10
11   # Menu item with Yad
12   printer=$(yad --title="PRINT PROGRAM" --text="Select printer" --form \
13   --field="Printer":CB $pline \
14   --button="Cancel":1 \
15   --button="Next":2)
16   if [ $? -eq 1 ]; then
17     exit
18   fi
19   printer=$(echo $printer | tr -d \| )
20
21   # Print sample file
22   file=$(yad --title="PRINT PROGRAM" --file)
23   yad --title="PRINT PROGRAM" --text="Print selected file $file?" --yesno
24   if [ $? -eq 0 ]; then
25     lpr -P$printer $file
26   fi
27   exit 0
28 }
29 prin

The yad calls in lines 12, 22, and 23 first ask for the desired printer (Figure 7), then open a dialog for file selection (Figure 8), and finally show a confirmation.

Figure 7: A Bash script can also be used to implement programs with graphical dialogs as in Listing 4.
Figure 8: The YAD command-line tool supports selection lists, file dialogs, and simple buttons.

Scripted Printing

Constantly recurring tasks, such as a database query, can be easily automated using a shell script. However, the command-line tools usually output the results without printable formatting.

With a little help from the enscript command, the output can be processed quite easily. enscript writes the result directly to a PostScript (PS) file and also supports printing the output content. This is used in the sample script from Listing 5.

Listing 5

Process Output

01 #!/bin/bash
02 # Database query (PostgreSQL) with print preparation
03
04 # Select PDF file or print
05 approach=$(echo "Print PDF" | smenu )
06 if [ "$approach" = "Print" ]; then
07   # Select printer
08   target=$(/usr/sbin/lpc status all | grep \: | tr -d \: | smenu -n3 -c -m "Choose a printer:")
09   # Database query, character set conversion, print preparation and printing
10   psql -P border=3 -c "select * from parts;" | recode UTF8..ISO-8859-15 | enscript -H1 --highlight-bar-gray=0.8 -fCourierBold10 -P$target
11 elif [ "$approach" = "PDF" ]; then
12   # Database query, character set conversion, generate PS
13   psql -P border=3 -c "select * from parts;" | recode UTF8..ISO-8859-15 | enscript -H1 --highlight-bar-gray=0.8 -fCourierBold10 -o partlist.ps
14   # Convert to PDF file
15   ps2pdf14 partlist.ps
16   # Delete PS file
17   rm -v partlist.ps
18   echo "Query saved in partlist.pdf"
19 fi

However, it is important to note that Enscript cannot handle UTF-8 encoded files and pipes. You need to convert the data to the desired character set in advance using recode. Both programs work both in a pipe and with files. If necessary, the PS files can also be converted to PDF format using Ps2pdf14.

The sample script in Listing 5 still offers plenty of scope for improvements and your own ideas. The process flow is shown in Figure 9, and the database query's output is shown in Figure 10. The script is primarily intended to demonstrate how little effort it takes to solve even very complex tasks. Compared to the clicks required with a database client from an office package, the terminal script saves a huge amount of work.

Figure 9: Listing 5 automates querying a PostgreSQL database. The script first prints the results directly and then writes a PDF file.
Figure 10: This is how the database query leaves the printer. The enscript command-line tool prepares the results.

Preparing the Output

The call to enscript (lines 10 and 13 of Listing 5) can be adapted to suit your own needs, if required. For example, you can opt to print in landscape format, specify the type and size of the font, and even output source code with syntax highlighting (see the "Source Code in Color" box). Some of the corresponding options are listed in Table 3.

Table 3

enscript Options

Action

Option

Note

Column specification

-<Number>

Specification of the pages to be printed

-a<FirstPage>-<LastPage>

Print odd pages

-a odd

Print even pages

-a even

Suppress page header

-B

Suppress job header

-h

Curtail over-length lines

-c

Specify printer

-d <printer>

Also possible, -P <printer>

Duplex printing

-DDuplex

Syntax highlighting

-E<language>

Output overview with enscript --help-highlight (in newer versions also enscript --help-pretty-print)

Text font

-f<font size>

Header font

-F<font size>

Reading lines

-H<number>

<number> outputs the frequency of reading lines; -H1 results in a "zebra crossing" with alternating light and dark lines

Specify grayscale for reading lines

--highlight-bar-gray=<value>

Title

-t

Multiple copy

-n <number>

Output file

-o <file>

-p <file> also possible

Landscape format

-r

Footer

-u<Text>

Multiple logical pages per page

-U <number>

<number> must be 2 or a multiple of it

For example, it is often necessary to avoid line breaks. If the lines are too long, it helps to use a smaller font or print in landscape format. This problem can also be solved by scripting. The wc -L command lets you determine the length of the longest occurring line. You can then use the value obtained in this way as a criterion for determining the font size and page orientation:

  • Up to 80 characters: 10/12pt font size
  • 80-132 characters: 8pt font size or 10/12pt and landscape format.
  • 132 characters or more: 8/10pt font size and landscape orientation.

Listing 6 shows a sub-script that uses wc to determine the longest line (Line 7) and then tells enscript to print in landscape mode or leave it in portrait mode with the conventional orientation (if loop starting at line 10).

Listing 6

Choose Page Orientation

01 #!/bin/bash
02
03 # File selection
04 file=$(ls -1 | smenu -n 10 -t 4)
05
06 # maximum line length
07 mz=$(cat $file | wc -L)
08
09 # Portrait up to 80 characters, landscape above this
10 if [ $mz -lt 80 ]; then
11         cat $file | recode UTF8..ISO-8859-15 | enscript -H1 --highlight-bar-gray=0.8 -fCourierBold10 -o $file.ps
12 elif [ $mz -gt 80 ]; then
13         cat $file | recode UTF8..ISO-8859-15 | enscript -r -H1 --highlight-bar-gray=0.8 -fCourierBold10 -o $file.ps
14 fi
15
16 [... Print commands, PDF conversion ...]

Conclusions

Even in the shell and in scripts, you do not have to do without the convenience that graphical interfaces offer when printing. Printer selection, queue management, and the creation of attractive print output can be easily integrated into your shell scripts. And you don't have to reinvent the wheel or learn programming. Simple shell scripts and practical command line tools take much of the work off your hands.

Source Code in Color

Text editors intended for programming usually color highlight commands, variables, or instructions; this makes it far easier to keep track of the source code. enscript also offers this kind of function with the -E<Language> option. A list of all supported schemas can be obtained with the enscript --help-highlight or enscript --help-pretty-print commands, depending on the version. For example, the command

enscript -H1 --highlight-bar-gray=08 -fCourierBold10 --color -Ebash -o Source.sh.ps Source.sh

creates a colored image of the Source.sh shell script (Figure 11). Before doing this, the correct character set again had to be set with recode.

Figure 11: Optionally, the Enscript output can also use syntax highlighting, to improve the source code printout.

Infos

  1. lp manpage: http://manpages.org/lp
  2. lpr manpage: http://manpages.org/lpr
  3. "Create a select menu with smenu" by Harald Zisler, Linux Magazine, Issue 205, December 2017, p. 32, http://www.linux-magazine.com/Issues/2017/205/smenu

The Author

Harald Zisler has been working with FreeBSD and Linux since the early 1990s. He writes magazine articles and books on technical and IT topics.