前幾章我們學(xué)習(xí)了如何操控文本,下面要做的是將文本呈于紙上。在這章中,我們將會著手用于打印文件和控制打印選項的命令行工具。通常不同發(fā)行版的打印配置各有不同且都會在其安裝時自動完成,因此這里我們不討論打印的配置過程。本章的練習(xí)需要一臺正確配置的打印機來完成。
我們將討論一下命令:
> * pr —— 轉(zhuǎn)換需要打印的文本文件
> * lpr —— 打印文件
> * lp —— 打印文件(System V)
> * a2ps —— 為 PostScript 打印機格式化文件
> * lpstat —— 顯示打印機狀態(tài)信息
> * lpq —— 顯示打印機隊列狀態(tài)
> * lprm —— 取消打印任務(wù)
> * cancel —— 取消打印任務(wù)(System V)
## 打印簡史
為了較好的理解類 Unix 操作系統(tǒng)中的打印功能,我們必須先了解一些歷史。類 Unix 系統(tǒng)中的打印可追溯到操作系統(tǒng)本身的起源,那時候打印機和它的用法與今天截然不同。
### 早期的打印
和計算機一樣,前 PC 時代的打印機都很大、很貴,并且很集中。1980年的計算機用戶都是在離電腦很遠的地方用一個連接電腦的終端來工作的,而打印機就放在電腦旁并受到計算機管理員的全方位監(jiān)視。
由于當(dāng)時打印機既昂貴又集中,而且都工作在早期的 Unix 環(huán)境下,人們從實際考慮通常都會多人共享一臺打印機。為了區(qū)別不同用戶的打印任務(wù),每個打印任務(wù)的開頭都會打印一張寫著用戶名字的標(biāo)題頁,然后計算機工作人員會用推車裝好當(dāng)天的打印任務(wù)并分發(fā)給每個用戶。
### 基于字符的打印機
80年代的打印機技術(shù)有兩方面的不同。首先,那時的打印機基本上都是打擊式打印機。打擊式打印機使用撞針打擊色帶的機械結(jié)構(gòu)在紙上形成字符。這種流行的技術(shù)造就了當(dāng)時的菊輪式打印和點陣式打印。
其次,更重要的是,早期打印機的特點是它使用設(shè)備內(nèi)部固定的一組字符集。比如,一臺菊輪式打印機只能打印固定在其菊花輪花瓣上的字符,就這點而言打印機更像是高速打字機。大部分打字機都使用等寬字體,意思是說每個字符的寬度相等,頁面上只有固定的區(qū)域可供打印,而這些區(qū)域只能容納固定的字符數(shù)。大部分打印機采用橫向10字符每英寸(CPI)和縱向6行每英寸(LPI)的規(guī)格打印,這樣一張美式信片紙就有橫向85字符寬縱向66行高,加上兩側(cè)的頁邊距,一行的最大寬度可達80字符。據(jù)此,使用等寬字體就能提供所見即所得(WYSIWYG,What You See Is What You Get)的打印預(yù)覽。
接著,一臺類打字機的打印機會收到以簡單字節(jié)流的形式傳送來的數(shù)據(jù),其中就包含要打印的字符。例如要打印一個字母a,計算機就會發(fā)送 ASCII 碼97,如果要移動打印機的滑動架和紙張,就需要使用回車、換行、換頁等的小編號 ASCII 控制碼。使用控制碼,還能實現(xiàn)一些之前受限制的字體效果,比如粗體,就是讓打印機先打印一個字符,然后退格再打印一遍來得到顏色較深的效果的。用 nroff 來產(chǎn)生一個手冊頁然后用 cat -A 檢查輸出,我們就能親眼看看這種效果了:
~~~
[me@linuxbox ~]$ zcat /usr/share/man/man1/ls.1.gz | nroff -man | cat -A | head
LS(1) User Commands LS(1)
$
N^HNA^HAM^HME^HE$
ls - list directory contents$
$
S^HSY^HYN^HNO^HOP^HPS^HSI^HIS^HS$
l^Hls^Hs [_^HO_^HP_^HT_^HI_^HO_^HN]... [_^HF_^HI_^HL_^HE]...$
~~~
^H(ctrl-H)字符是用于打印粗體效果的退格符。同樣,我們還可以看到用于打印下劃線效果的[退格/下劃線]序列。
### 圖形化打印機
圖形用戶界面(GUI)的發(fā)展催生了打印機技術(shù)中主要的變革。隨著計算機的展現(xiàn)步入更多以圖形為基礎(chǔ)的方式,打印技術(shù)也從基于字符走向圖形化技術(shù),這一切都是源于激光打印機的到來,它不僅廉價,還可以在打印區(qū)域的任意位置打印微小的墨點,而不是使用固定的字符集。這讓打印機能夠打印成比例的字體(像用排字機那樣),甚至是圖片和高質(zhì)量圖表。
然而,從基于字符的方式到轉(zhuǎn)移到圖形化的方式提出了一個嚴峻的技術(shù)挑戰(zhàn)。原因如下:使用基于字符的打印機時,填滿一張紙所用的字節(jié)數(shù)可以這樣計算出來(假設(shè)一張紙有60行,每行80個字符):60 × 80 = 4800字節(jié)。
相比之下,用一臺300點每英寸(DPI)分辨率的激光打印機(假設(shè)一張紙有8乘10英寸的打印區(qū)域)打印則需要 (8 × 300) × (10 × 300) / 8 = 900,000字節(jié)。
當(dāng)時許多慢速的個人電腦網(wǎng)絡(luò)無法接受激光打印機打印一頁需要傳輸將近1兆的數(shù)據(jù)這一點,因此,很有必要發(fā)明一種更聰明的方法。
這種發(fā)明便是頁面描述語言(PDL)。PDL 是一種描述頁面內(nèi)容的編程語言。簡單的說就是,“到這個地方,印一個10點大小的黑體字符 a ,到這個地方。。。” 這樣直到頁面上的所有內(nèi)容都描述完了。第一種主要的 PDL 是 Adobe 系統(tǒng)開發(fā)的 PostScript,直到今天,這種語言仍被廣泛使用。PostScript 是專為印刷各類圖形和圖像設(shè)計的完整的編程語言,它內(nèi)建支持35種標(biāo)準(zhǔn)的高質(zhì)量字體,在工作是還能夠接受其他的字體定義。最早,對 PostScript 的支持是打印機本身內(nèi)建的。這樣傳輸數(shù)據(jù)的問題就解決了。相比基于字符打印機的簡單字節(jié)流,典型的 PostScript 程序更為詳細,而且比表示整個頁面的字節(jié)數(shù)要小很多。
一臺 PostScript 打印機接受 PostScript 程序作為輸入。打印機有自己的處理器和內(nèi)存(通常這讓打印機比連接它的計算機更為強大),能執(zhí)行一種叫做 PostScript 解析器的特殊程序用于讀取輸入的 PostScript 程序并生成結(jié)果導(dǎo)入打印機的內(nèi)存,這樣就形成了要轉(zhuǎn)移到紙上的位(點)圖。這種將頁面渲染成大型位圖(bitmap)的過程有個通用名稱作光柵圖像處理器(raster image processor),又叫 RIP。
多年之后,電腦和網(wǎng)絡(luò)都變得更快了。這使得 RIP 技術(shù)從打印機轉(zhuǎn)移到了主機上,還讓高品質(zhì)打印機變得更便宜了。
現(xiàn)在的許多打印機仍能接受基于字符的字節(jié)流,但很多廉價的打印機卻不支持,因為它們依賴于主機的 RIP 提供的比特流來作為點陣打印。當(dāng)然也有不少仍舊是 PostScript 打印機。
## 在 Linux 下打印
當(dāng)前 Linux 系統(tǒng)采用兩套軟件配合顯示和管理打印。第一,CUPS(Common Unix Printing System,一般 Unix 打印系統(tǒng)),用于提供打印驅(qū)動和打印任務(wù)管理;第二,Ghostscript,一種 PostScript 解析器,作為 RIP 使用。
CUPS 通過創(chuàng)建并維護打印隊列來管理打印機。如前所述,Unix 下的打印原本是設(shè)計成多用戶共享中央打印機的管理模式的。由于打印機本身比連接到它的電腦要慢,打印系統(tǒng)就需要對打印任務(wù)進行調(diào)度使其保持順序。CUPS 還能識別出不同類型的數(shù)據(jù)(在合理范圍內(nèi))并轉(zhuǎn)換文件為可打印的格式。
## 為打印準(zhǔn)備文件
作為命令行用戶,盡管打印各種格式的文本都能實現(xiàn),不過打印最多的,還是文本。
### pr - 轉(zhuǎn)換需要打印的文本文件
前面的章節(jié)我們也有提到過 pr 命令,現(xiàn)在我們來探討一下這條命令結(jié)合打印使用的一些選項。我們知道,在打印的歷史上,基于字符的打印機曾經(jīng)用過等寬字體,致使每頁只能打印固定的行數(shù)和字符數(shù),而 pr 命令則能夠根據(jù)不同的頁眉和頁邊距排列文本使其適應(yīng)指定的紙張。表23-1總結(jié)了最常用的選項。
表23-1: 常用 pr 選項
| 選項 | 描述 |
|-------|----------|
| +first[:last] | 輸出從 first 到 last(默認為最后)范圍內(nèi)的頁面。 |
| -columns | 根據(jù) columns 指定的列數(shù)排版頁面內(nèi)容。 |
| -a | 默認多列輸出為垂直,用 -a (across)可使其水平輸出。 |
| -d | 雙空格輸出。 |
| -D format | 用 format 指定的格式修改頁眉中顯示的日期,日期命令中 format 字符串的描述詳見參考手冊。 |
| -f | 改用換頁替換默認的回車來分割頁面。 |
| -h header | 在頁眉中部用 header 參數(shù)替換打印文件的名字。 |
| -l length | 設(shè)置頁長為 length,默認為66行(每英寸6行的美國信紙)。 |
| -n | 輸出行號。 |
| -o offset | 創(chuàng)建一個寬 offset 字符的左頁邊。 |
| -w width | 設(shè)置頁寬為 width,默認為72字符。 |
我們通常用管道配合 pr 命令來做篩選。下面的例子中我們會列出目錄 /usr/bin 并用 pr 將其格式化為3列輸出的標(biāo)題頁:
~~~
[me@linuxbox ~]$ ls /usr/bin | pr -3 -w 65 | head
2012-02-18 14:00 Page 1
[ apturl bsd-write
411toppm ar bsh
a2p arecord btcflash
a2ps arecordmidi bug-buddy
a2ps-lpr-wrapper ark buildhash
~~~
## 將打印任務(wù)送至打印機
CUPS 打印體系支持兩種曾用于類 Unix 系統(tǒng)的打印方式。一種,叫 Berkeley 或 LPD(用于 Unix 的 Berkeley 軟件發(fā)行版),使用 lpr 程序;另一種,叫 SysV(源自 System V 版本的 Unix),使用 lp 程序。這兩個程序的功能大致相同。具體使用哪個完全根據(jù)個人喜好。
### lpr - 打印文件(Berkeley 風(fēng)格)
lpr 程序可以用來把文件傳送給打印機。由于它能接收標(biāo)準(zhǔn)輸入,所以能用管道來協(xié)同工作。例如,要打印剛才多列目錄列表的結(jié)果,我們只需這樣:
~~~
[me@linuxbox ~]$ ls /usr/bin | pr -3 | lpr
~~~
報告會送到系統(tǒng)默認的打印機,如果要送到別的打印機,可以使用 -P 參數(shù):
~~~
lpr -P printer_name
~~~
printer_name 表示這臺打印機的名稱。若要查看系統(tǒng)已知的打印機列表:
~~~
[me@linuxbox ~]$ lpstat -a
~~~
注意:許多 Linux 發(fā)行版允許你定義一個輸出 PDF 文件但不執(zhí)行實體打印的“打印機”,這可以用來很方便的檢驗?zāi)愕拇蛴∶?。看看你的打印機配置程序是否支持這項配置。在某些發(fā)行版中,你可能要自己安裝額外的軟件包(如 cups-pdf)來使用這項功能。
表23-2顯示了 lpr 的一些常用選項
表23-2: 常用 lpr 選項
| 選項 | 描述 |
|-------|--------|
| -# number | 設(shè)定打印份數(shù)為 number。 |
| -p | 使每頁頁眉標(biāo)題中帶有日期、時間、工作名稱和頁碼。這種所謂的“美化打印”選項可用于打印文本文件。 |
| -P printer | 指定輸出打印機的名稱。未指定則使用系統(tǒng)默認打印機。 |
| -r | 打印后刪除文件。對程序產(chǎn)生的臨時打印文件較為有用。 |
### lp - 打印文件(System V 風(fēng)格)
和 lpr 一樣,lp 可以接收文件或標(biāo)準(zhǔn)輸入為打印內(nèi)容。與 lpr 不同的是 lp 支持不同的選項(略為復(fù)雜),表23-3列出了其常用選項。
表23-3: 常用 lp 選項
| 選項 | 描述 |
|-------|--------|
| -d printer | 設(shè)定目標(biāo)(打印機)為 printer。若d 選項未指定,則使用系統(tǒng)默認打印機。 |
| -n number | 設(shè)定的打印份數(shù)為 number。 |
| -o landscape | 設(shè)置輸出為橫向。 |
| -o fitplot | 縮放文件以適應(yīng)頁面。打印圖像時較為有用,如 JPEG 文件。 |
| -o scaling=number | 縮放文件至 number。100表示填滿頁面,小于100表示縮小,大于100則會打印在多頁上。 |
| -o cpi=number | 設(shè)定輸出為 number 字符每英寸。默認為10。 |
| -o lpi=number | 設(shè)定輸出為 number 行每英寸,默認為6。 |
| -o page-bottom=points
-o page-left=points
-o page-right=points
-o page-top=points | 設(shè)置頁邊距,單位為點,一種印刷上的單位。一英寸 =72點。 |
| -P pages | 指定打印的頁面。pages 可以是逗號分隔的列表或范圍——例如 1,3,5,7-10。 |
再次打印我們的目錄列表,這次我們設(shè)置12 CPI、8 LPI 和一個半英寸的左邊距。注意這里我必須調(diào)整 pr 選項來適應(yīng)新的頁面大小:
~~~
[me@linuxbox ~]$ ls /usr/bin | pr -4 -w 90 -l 88 | lp -o page-left=36 -o cpi=12 -o lpi=8
~~~
這條命令用小于默認的格式產(chǎn)生了一個四列的列表。增加 CPI 可以讓我們在頁面上打印更多列。
### 另一種選擇:a2ps
a2ps 程序很有趣。單從名字上看,這是個格式轉(zhuǎn)換程序,但它的功能不止于此。程序名字的本意為 ASCII to PostScript,它是用來為 PostScript 打印機準(zhǔn)備要打印的文本文件的。多年后,程序的功能得到了提升,名字的含義也變成了 Anything to PostScript。盡管名為格式轉(zhuǎn)換程序,但它實際的功能卻是打印。它的默認輸出不是標(biāo)準(zhǔn)輸出,而是系統(tǒng)的默認打印機。程序的默認行為被稱為“漂亮的打印機”,這意味著它可以改善輸出的外觀。我們能用程序在桌面上創(chuàng)建一個 PostScript 文件:
~~~
[me@linuxbox ~]$ ls /usr/bin | pr -3 -t | a2ps -o ~/Desktop/ls.ps -L 66
[stdin (plain): 11 pages on 6 sheets]
[Total: 11 pages on 6 sheets] saved into the file `/home/me/Desktop/ls.ps'
~~~
這里我們用帶 -t 參數(shù)(忽略頁眉和頁腳)的 pr 命令過濾數(shù)據(jù)流,然后用 a2ps 指定一個輸出文件(-o 參數(shù)),并設(shè)定每頁66行(-L 參數(shù))來匹配 pr 的輸出分頁。用合適的文件查看器查看我們的輸出文件,我們就會看到圖23-1中顯示的結(jié)果。

圖 23-1: 瀏覽 a2ps 的輸出結(jié)果
可以看到,默認的輸出布局是一面兩頁的,這將導(dǎo)致兩頁的內(nèi)容被打印到一張紙上。a2ps 還能利用頁眉和頁腳。
a2ps 有很多選項,總結(jié)在表23-4中。
表23-4: a2ps 選項
| 選項 | 描述 |
|------|-------|
| --center-title text | 設(shè)置中心頁標(biāo)題為 text。 |
| --columns number | 將所有頁面排列成 number 列。默認為2。 |
| --footer text | 設(shè)置頁腳為 text。 |
| --guess | 報告參數(shù)中文件的類型。由于 a2ps 會轉(zhuǎn)換并格式化所有類型的數(shù)據(jù),所以當(dāng)給定文件類型后,這個選項可以很好的用來判斷 a2ps 應(yīng)該做什么。 |
| --left-footer text | 設(shè)置左頁腳為 text。 |
| --left-title text | 設(shè)置頁面左標(biāo)題為 text。 |
| --line-numbers=interval | 每隔 interval 行輸出行號。 |
| --list=defauls | 顯示默認設(shè)置。 |
| --list=topic | 顯示 topic 設(shè)置,topic 表示下列之一:代理程序(用來轉(zhuǎn)換數(shù)據(jù)的外部程序),編碼,特征,變量,媒介(頁面大小等),ppd(PostScript 打印機描述信息),打印機,起始程序(為常規(guī)輸出添加前綴的代碼部分),樣式表,或用戶選項。 |
| --pages range | 打印 range 范圍內(nèi)的頁面。 |
| --right-footer text | 設(shè)置右頁腳為 text。 |
| --right-title text | 設(shè)置頁面右標(biāo)題為 text。 |
| --rows number | 將所有頁面排列成 number 排。默認為1。 |
| -B | 沒有頁眉。 |
| -b text | 設(shè)置頁眉為 text。 |
| -f size | 使用字體大小為 size 號。 |
| -l number | 設(shè)置每行字符數(shù)為 number。此項和 -L 選項(見下方)可以給文件用其他程序來更準(zhǔn)確的分頁,如 pr。 |
| -L number | 設(shè)置每頁行數(shù)為 number。 |
| -M name | 使用打印媒介的名稱——例如,A4。 |
| -n number | 每頁輸出 number 份。 |
| -o file | 輸出到文件 file。如果指定為 - ,則輸出到標(biāo)準(zhǔn)輸出。 |
| -P printer | 使用打印機 printer。如果未指定,則使用系統(tǒng)默認打印機。 |
| -R | 縱向打印。 |
| -r | 橫向打印。 |
| -T number | 設(shè)置制表位為每 number 字符。 |
| -u text | 用 text 作為頁面底圖(水?。?。 |
以上只是對 a2ps 的總結(jié),更多的選項尚未列出。
注意:a2ps 目前仍在不斷的開發(fā)中。就我的測試而言,不同版本之間都多少有所變化。CentOS 4 中輸出總是默認為標(biāo)準(zhǔn)輸出。在 CentOS 4 和 Fedora 10 中,盡管程序配置信紙為默認媒介,輸出還是默認為 A4紙。我可以明確的指定需要的選項來解決這些問題。Ubuntu 8.04 中,a2ps 表現(xiàn)的正如參考文檔中所述。 另外,我們也要注意到另一個轉(zhuǎn)換文本為 PostScript 的輸出格式化工具,名叫 enscript。它具有許多相同的格式化和打印功能,但和 a2ps 唯一的不同在于,它只能處理純文本的輸入。
## 監(jiān)視和控制打印任務(wù)
由于 Unix 打印系統(tǒng)的設(shè)計是能夠處理多用戶的多重打印任務(wù),CUPS 也是如此設(shè)計的。每臺打印機都有一個打印隊列,其中的任務(wù)直到傳送到打印機才停下并進行打印。CUPS 支持一些命令行程序來管理打印機狀態(tài)和打印隊列。想 lpr 和 lp 這樣的管理程序都是以 Berkeley 和 System V 打印系統(tǒng)的相應(yīng)程序為依據(jù)進行排列的。
### lpstat - 顯示打印系統(tǒng)狀態(tài)
lpstat 程序可用于確定系統(tǒng)中打印機的名字和有效性。例如,我們系統(tǒng)中有一臺實體打印機(名叫 printer)和一臺 PDF 虛擬打印機(名叫 PDF),我們可以像這樣查看打印機狀態(tài):
~~~
[me@linuxbox ~]$ lpstat -a
PDF accepting requests since Mon 05 Dec 2011 03:05:59 PM EST
printer accepting requests since Tue 21 Feb 2012 08:43:22 AM EST
~~~
接著,我們可以查看打印系統(tǒng)更具體的配置信息:
~~~
[me@linuxbox ~]$ lpstat -s
system default destination: printer
device for PDF: cups-pdf:/
device for printer: ipp://print-server:631/printers/printer
~~~
上例中,我們看到 printer 是系統(tǒng)默認的打印機,其本身是一臺網(wǎng)絡(luò)打印機,使用網(wǎng)絡(luò)打印協(xié)議(ipp://)通過網(wǎng)絡(luò)連接到名為 print-server 的系統(tǒng)。
lpstat 的常用選項列于表23-5。
表23-5: 常用 lpstat 選項
| 選項 | 描述 |
|------|-------|
| -a [printer...] | 顯示 printer 打印機的隊列。這里顯示的狀態(tài)是打印機隊列承受任務(wù)的能力,而不是實體打印機的狀態(tài)。若未指定打印機,則顯示所有打印隊列。 |
| -d | 顯示系統(tǒng)默認打印機的名稱。 |
| -p [printer...] | 顯示 printer 指定的打印機的狀態(tài)。若未指定打印機,則顯示所有打印機狀態(tài)。 |
| -r | 顯示打印系統(tǒng)的狀態(tài)。 |
| -s | 顯示匯總狀態(tài)。 |
| -t | 顯示完整狀態(tài)報告。 |
### lpq - 顯示打印機隊列狀態(tài)
使用 lpq 程序可以查看打印機隊列的狀態(tài),從中我們可以看到隊列的狀態(tài)和所包含的打印任務(wù)。下面的例子顯示了一臺名叫 printer 的系統(tǒng)默認打印機包含一個空隊列的情況:
~~~
[me@linuxbox ~]$ lpq
printer is ready
no entries
~~~
如果我們不指定打印機(用 -P 參數(shù)),就會顯示系統(tǒng)默認打印機。如果給打印機添加一項任務(wù)再查看隊列,我們就會看到下列結(jié)果:
~~~
[me@linuxbox ~]$ ls *.txt | pr -3 | lp
request id is printer-603 (1 file(s))
[me@linuxbox ~]$ lpq
printer is ready and printing
Rank Owner Job File(s) Total Size
active me 603 (stdin) 1024 bytes
~~~
### lprm 和 cancel - 取消打印任務(wù)
CUPS 提供兩個程序來從打印隊列中終止并移除打印任務(wù)。一個是 Berkeley 風(fēng)格的(lprm),另一個是 System V 的(cancel)。在支持的選項上兩者有較小的區(qū)別但是功能卻幾乎相同。以上面的打印任務(wù)為例,我們可以像這樣終止并移除任務(wù):
~~~
[me@linuxbox ~]$ cancel 603
[me@linuxbox ~]$ lpq
printer is ready
no entries
~~~
每個命令都有選項可用于移除某用戶、某打印機或多個任務(wù)號的所有任務(wù),相應(yīng)的參考手冊中都有詳細的介紹。
- 第一章:引言
- 第二章:什么是shell
- 第三章:文件系統(tǒng)中跳轉(zhuǎn)
- 第四章:研究操作系統(tǒng)
- 第五章:操作文件和目錄
- 第六章:使用命令
- 第七章:重定向
- 第八章:從shell眼中看世界
- 第九章:鍵盤高級操作技巧
- 第十章:權(quán)限
- 第十一章:進程
- 第十二章:shell環(huán)境
- 第十三章:VI簡介
- 第十四章:自定制shell提示符
- 第十五章:軟件包管理
- 第十六章:存儲媒介
- 第十七章:網(wǎng)絡(luò)系統(tǒng)
- 第十八章:查找文件
- 第十九章:歸檔和備份
- 第二十章:正則表達式
- 第二十一章:文本處理
- 第二十二章:格式化輸出
- 第二十三章:打印
- 第二十四章:編譯程序
- 第二十五章:編寫第一個shell腳本
- 第二十六章:啟動一個項目
- 第二十七章:自頂向下設(shè)計
- 第二十八章:流程控制 if分支結(jié)構(gòu)
- 第二十九章:讀取鍵盤輸入
- 第三十章:流程控制 while/until 循環(huán)
- 第三十一章:疑難排解
- 第三十二章:流程控制 case分支
- 第三十三章:位置參數(shù)
- 第三十四章:流程控制 for循環(huán)
- 第三十五章:字符串和數(shù)字
- 第三十六章:數(shù)組
- 第三十七章:奇珍異寶
