前幾章我們學(xué)習(xí)了如何操控文本,下面要做的是將文本呈于紙上。在這章中,我們將會著手用于打印文件和控制打印選項(xiàng)的命令行工具。通常不同發(fā)行版的打印配置各有不同且都會在其安裝時(shí)自動完成,因此這里我們不討論打印的配置過程。本章的練習(xí)需要一臺正確配置的打印機(jī)來完成。
我們將討論一下命令:
pr —— 轉(zhuǎn)換需要打印的文本文件
lpr —— 打印文件
lp —— 打印文件(System V)
a2ps —— 為 PostScript 打印機(jī)格式化文件
lpstat —— 顯示打印機(jī)狀態(tài)信息
lpq —— 顯示打印機(jī)隊(duì)列狀態(tài)
lprm —— 取消打印任務(wù)
為了較好的理解類 Unix 操作系統(tǒng)中的打印功能,我們必須先了解一些歷史。類 Unix 系統(tǒng)中的打印可追溯到操作系統(tǒng)本身的起源,那時(shí)候打印機(jī)和它的用法與今天截然不同。
和計(jì)算機(jī)一樣,前 PC 時(shí)代的打印機(jī)都很大、很貴,并且很集中。1980年的計(jì)算機(jī)用戶都是在離電腦很遠(yuǎn)的地方用一個(gè)連接電腦的終端來工作的,而打印機(jī)就放在電腦旁并受到計(jì)算機(jī)管理員的全方位監(jiān)視。
由于當(dāng)時(shí)打印機(jī)既昂貴又集中,而且都工作在早期的 Unix 環(huán)境下,人們從實(shí)際考慮通常都會多人共享一臺打印機(jī)。為了區(qū)別不同用戶的打印任務(wù),每個(gè)打印任務(wù)的開頭都會打印一張寫著用戶名字的標(biāo)題頁,然后計(jì)算機(jī)工作人員會用推車裝好當(dāng)天的打印任務(wù)并分發(fā)給每個(gè)用戶。
80年代的打印機(jī)技術(shù)有兩方面的不同。首先,那時(shí)的打印機(jī)基本上都是打擊式打印機(jī)。打擊式打印機(jī)使用撞針打擊色帶的機(jī)械結(jié)構(gòu)在紙上形成字符。這種流行的技術(shù)造就了當(dāng)時(shí)的菊輪式打印和點(diǎn)陣式打印。
其次,更重要的是,早期打印機(jī)的特點(diǎn)是它使用設(shè)備內(nèi)部固定的一組字符集。比如,一臺菊輪式打印機(jī)只能打印固定在其菊花輪花瓣上的字符,就這點(diǎn)而言打印機(jī)更像是高速打字機(jī)。大部分打字機(jī)都使用等寬字體,意思是說每個(gè)字符的寬度相等,頁面上只有固定的區(qū)域可供打印,而這些區(qū)域只能容納固定的字符數(shù)。大部分打印機(jī)采用橫向10字符每英寸(CPI)和縱向6行每英寸(LPI)的規(guī)格打印,這樣一張美式信片紙就有橫向85字符寬縱向66行高,加上兩側(cè)的頁邊距,一行的最大寬度可達(dá)80字符。據(jù)此,使用等寬字體就能提供所見即所得(WYSIWYG,What You See Is What You Get)的打印預(yù)覽。
接著,一臺類打字機(jī)的打印機(jī)會收到以簡單字節(jié)流的形式傳送來的數(shù)據(jù),其中就包含要打印的字符。例如要打印一個(gè)字母a,計(jì)算機(jī)就會發(fā)送 ASCII 碼97,如果要移動打印機(jī)的滑動架和紙張,就需要使用回車、換行、換頁等的小編號 ASCII 控制碼。使用控制碼,還能實(shí)現(xiàn)一些之前受限制的字體效果,比如粗體,就是讓打印機(jī)先打印一個(gè)字符,然后退格再打印一遍來得到顏色較深的效果的。用 nroff 來產(chǎn)生一個(gè)手冊頁然后用 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ā)展催生了打印機(jī)技術(shù)中主要的變革。隨著計(jì)算機(jī)的展現(xiàn)步入更多以圖形為基礎(chǔ)的方式,打印技術(shù)也從基于字符走向圖形化技術(shù),這一切都是源于激光打印機(jī)的到來,它不僅廉價(jià),還可以在打印區(qū)域的任意位置打印微小的墨點(diǎn),而不是使用固定的字符集。這讓打印機(jī)能夠打印成比例的字體(像用排字機(jī)那樣),甚至是圖片和高質(zhì)量圖表。
然而,從基于字符的方式到轉(zhuǎn)移到圖形化的方式提出了一個(gè)嚴(yán)峻的技術(shù)挑戰(zhàn)。原因如下:使用基于字符的打印機(jī)時(shí),填滿一張紙所用的字節(jié)數(shù)可以這樣計(jì)算出來(假設(shè)一張紙有60行,每行80個(gè)字符):60 × 80 = 4800字節(jié)。
相比之下,用一臺300點(diǎn)每英寸(DPI)分辨率的激光打印機(jī)(假設(shè)一張紙有8乘10英寸的打印區(qū)域)打印則需要 (8 × 300) × (10 × 300) / 8 = 900,000字節(jié)。
當(dāng)時(shí)許多慢速的個(gè)人電腦網(wǎng)絡(luò)無法接受激光打印機(jī)打印一頁需要傳輸將近1兆的數(shù)據(jù)這一點(diǎn),因此,很有必要發(fā)明一種更聰明的方法。
這種發(fā)明便是頁面描述語言(PDL)。PDL 是一種描述頁面內(nèi)容的編程語言。簡單的說就是,“到這個(gè)地方,印一個(gè)10點(diǎn)大小的黑體字符 a ,到這個(gè)地方。。。” 這樣直到頁面上的所有內(nèi)容都描述完了。第一種主要的 PDL 是 Adobe 系統(tǒng)開發(fā)的 PostScript,直到今天,這種語言仍被廣泛使用。PostScript 是專為印刷各類圖形和圖像設(shè)計(jì)的完整的編程語言,它內(nèi)建支持35種標(biāo)準(zhǔn)的高質(zhì)量字體,在工作是還能夠接受其他的字體定義。最早,對 PostScript 的支持是打印機(jī)本身內(nèi)建的。這樣傳輸數(shù)據(jù)的問題就解決了。相比基于字符打印機(jī)的簡單字節(jié)流,典型的 PostScript 程序更為詳細(xì),而且比表示整個(gè)頁面的字節(jié)數(shù)要小很多。
一臺 PostScript 打印機(jī)接受 PostScript 程序作為輸入。打印機(jī)有自己的處理器和內(nèi)存(通常這讓打印機(jī)比連接它的計(jì)算機(jī)更為強(qiáng)大),能執(zhí)行一種叫做 PostScript 解析器的特殊程序用于讀取輸入的 PostScript 程序并生成結(jié)果導(dǎo)入打印機(jī)的內(nèi)存,這樣就形成了要轉(zhuǎn)移到紙上的位(點(diǎn))圖。這種將頁面渲染成大型位圖(bitmap)的過程有個(gè)通用名稱作光柵圖像處理器(raster image processor),又叫 RIP。
多年之后,電腦和網(wǎng)絡(luò)都變得更快了。這使得 RIP 技術(shù)從打印機(jī)轉(zhuǎn)移到了主機(jī)上,還讓高品質(zhì)打印機(jī)變得更便宜了。
現(xiàn)在的許多打印機(jī)仍能接受基于字符的字節(jié)流,但很多廉價(jià)的打印機(jī)卻不支持,因?yàn)樗鼈円蕾囉谥鳈C(jī)的 RIP 提供的比特流來作為點(diǎn)陣打印。當(dāng)然也有不少仍舊是 PostScript 打印機(jī)。
當(dāng)前 Linux 系統(tǒng)采用兩套軟件配合顯示和管理打印。第一,CUPS(Common Unix Printing System,一般 Unix 打印系統(tǒng)),用于提供打印驅(qū)動和打印任務(wù)管理;第二,Ghostscript,一種 PostScript 解析器,作為 RIP 使用。
CUPS 通過創(chuàng)建并維護(hù)打印隊(duì)列來管理打印機(jī)。如前所述,Unix 下的打印原本是設(shè)計(jì)成多用戶共享中央打印機(jī)的管理模式的。由于打印機(jī)本身比連接到它的電腦要慢,打印系統(tǒng)就需要對打印任務(wù)進(jìn)行調(diào)度使其保持順序。CUPS 還能識別出不同類型的數(shù)據(jù)(在合理范圍內(nèi))并轉(zhuǎn)換文件為可打印的格式。
作為命令行用戶,盡管打印各種格式的文本都能實(shí)現(xiàn),不過打印最多的,還是文本。
前面的章節(jié)我們也有提到過 pr 命令,現(xiàn)在我們來探討一下這條命令結(jié)合打印使用的一些選項(xiàng)。我們知道,在打印的歷史上,基于字符的打印機(jī)曾經(jīng)用過等寬字體,致使每頁只能打印固定的行數(shù)和字符數(shù),而 pr 命令則能夠根據(jù)不同的頁眉和頁邊距排列文本使其適應(yīng)指定的紙張。表23-1總結(jié)了最常用的選項(xiàng)。
| 選項(xiàng) | 描述 |
|---|---|
| +first[:last] | 輸出從 first 到 last(默認(rèn)為最后)范圍內(nèi)的頁面。 |
| -columns | 根據(jù) columns 指定的列數(shù)排版頁面內(nèi)容。 |
| -a | 默認(rèn)多列輸出為垂直,用 -a (across)可使其水平輸出。 |
| -d | 雙空格輸出。 |
| -D format | 用 format 指定的格式修改頁眉中顯示的日期,日期命令中 format 字符串的描述詳見參考手冊。 |
| -f | 改用換頁替換默認(rèn)的回車來分割頁面。 |
| -h header | 在頁眉中部用 header 參數(shù)替換打印文件的名字。 |
| -l length | 設(shè)置頁長為 length,默認(rèn)為66行(每英寸6行的美國信紙)。 |
| -n | 輸出行號。 |
| -o offset | 創(chuàng)建一個(gè)寬 offset 字符的左頁邊。 |
| -w width | 設(shè)置頁寬為 width,默認(rèn)為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
CUPS 打印體系支持兩種曾用于類 Unix 系統(tǒng)的打印方式。一種,叫 Berkeley 或 LPD(用于 Unix 的 Berkeley 軟件發(fā)行版),使用 lpr 程序;另一種,叫 SysV(源自 System V 版本的 Unix),使用 lp 程序。這兩個(gè)程序的功能大致相同。具體使用哪個(gè)完全根據(jù)個(gè)人喜好。
lpr 程序可以用來把文件傳送給打印機(jī)。由于它能接收標(biāo)準(zhǔn)輸入,所以能用管道來協(xié)同工作。例如,要打印剛才多列目錄列表的結(jié)果,我們只需這樣:
[me@linuxbox ~]$ ls /usr/bin | pr -3 | lpr
報(bào)告會送到系統(tǒng)默認(rèn)的打印機(jī),如果要送到別的打印機(jī),可以使用 -P 參數(shù):
lpr -P printer_name
printer_name 表示這臺打印機(jī)的名稱。若要查看系統(tǒng)已知的打印機(jī)列表:
[me@linuxbox ~]$ lpstat -a
注意:許多 Linux 發(fā)行版允許你定義一個(gè)輸出 PDF 文件但不執(zhí)行實(shí)體打印的“打印機(jī)”,這可以用來很方便的檢驗(yàn)?zāi)愕拇蛴∶睢?纯茨愕拇蛴C(jī)配置程序是否支持這項(xiàng)配置。在某些發(fā)行版中,你可能要自己安裝額外的軟件包(如 cups-pdf)來使用這項(xiàng)功能。
表23-2顯示了 lpr 的一些常用選項(xiàng)
| 選項(xiàng) | 描述 |
|---|---|
| -# number | 設(shè)定打印份數(shù)為 number。 |
| -p | 使每頁頁眉標(biāo)題中帶有日期、時(shí)間、工作名稱和頁碼。這種所謂的“美化打印”選項(xiàng)可用于打印文本文件。 |
| -P printer | 指定輸出打印機(jī)的名稱。未指定則使用系統(tǒng)默認(rèn)打印機(jī)。 |
| -r | 打印后刪除文件。對程序產(chǎn)生的臨時(shí)打印文件較為有用。 |
和 lpr 一樣,lp 可以接收文件或標(biāo)準(zhǔn)輸入為打印內(nèi)容。與 lpr 不同的是 lp 支持不同的選項(xiàng)(略為復(fù)雜),表23-3列出了其常用選項(xiàng)。
| 選項(xiàng) | 描述 |
|---|---|
| -d printer | 設(shè)定目標(biāo)(打印機(jī))為 printer。若d 選項(xiàng)未指定,則使用系統(tǒng)默認(rèn)打印機(jī)。 |
| -n number | 設(shè)定的打印份數(shù)為 number。 |
| -o landscape | 設(shè)置輸出為橫向。 |
| -o fitplot | 縮放文件以適應(yīng)頁面。打印圖像時(shí)較為有用,如 JPEG 文件。 |
| -o scaling=number | 縮放文件至 number。100表示填滿頁面,小于100表示縮小,大于100則會打印在多頁上。 |
| -o cpi=number | 設(shè)定輸出為 number 字符每英寸。默認(rèn)為10。 |
| -o lpi=number | 設(shè)定輸出為 number 行每英寸,默認(rèn)為6。 |
| -o page-bottom=points -o page-left=points -o page-right=points -o page-top=points |
設(shè)置頁邊距,單位為點(diǎn),一種印刷上的單位。一英寸 =72點(diǎn)。 |
| -P pages | 指定打印的頁面。pages 可以是逗號分隔的列表或范圍——例如 1,3,5,7-10。 |
再次打印我們的目錄列表,這次我們設(shè)置12 CPI、8 LPI 和一個(gè)半英寸的左邊距。注意這里我必須調(diào)整 pr 選項(xiàng)來適應(yīng)新的頁面大小:
[me@linuxbox ~]$ ls /usr/bin | pr -4 -w 90 -l 88 | lp -o page-left=36 -o cpi=12 -o lpi=8
這條命令用小于默認(rèn)的格式產(chǎn)生了一個(gè)四列的列表。增加 CPI 可以讓我們在頁面上打印更多列。
a2ps 程序很有趣。單從名字上看,這是個(gè)格式轉(zhuǎn)換程序,但它的功能不止于此。程序名字的本意為 ASCII to PostScript,它是用來為 PostScript 打印機(jī)準(zhǔn)備要打印的文本文件的。多年后,程序的功能得到了提升,名字的含義也變成了 Anything to PostScript。盡管名為格式轉(zhuǎn)換程序,但它實(shí)際的功能卻是打印。它的默認(rèn)輸出不是標(biāo)準(zhǔn)輸出,而是系統(tǒng)的默認(rèn)打印機(jī)。程序的默認(rèn)行為被稱為“漂亮的打印機(jī)”,這意味著它可以改善輸出的外觀。我們能用程序在桌面上創(chuàng)建一個(gè) 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 指定一個(gè)輸出文件(-o 參數(shù)),并設(shè)定每頁66行(-L 參數(shù))來匹配 pr 的輸出分頁。用合適的文件查看器查看我們的輸出文件,我們就會看到圖23-1中顯示的結(jié)果。
\
圖 23-1: 瀏覽 a2ps 的輸出結(jié)果
{: .figure}
可以看到,默認(rèn)的輸出布局是一面兩頁的,這將導(dǎo)致兩頁的內(nèi)容被打印到一張紙上。a2ps 還能利用頁眉和頁腳。
a2ps 有很多選項(xiàng),總結(jié)在表23-4中。
| 選項(xiàng) | 描述 |
|---|---|
| --center-title text | 設(shè)置中心頁標(biāo)題為 text。 |
| --columns number | 將所有頁面排列成 number 列。默認(rèn)為2。 |
| --footer text | 設(shè)置頁腳為 text。 |
| --guess | 報(bào)告參數(shù)中文件的類型。由于 a2ps 會轉(zhuǎn)換并格式化所有類型的數(shù)據(jù),所以當(dāng)給定文件類型后,這個(gè)選項(xiàng)可以很好的用來判斷 a2ps 應(yīng)該做什么。 |
| --left-footer text | 設(shè)置左頁腳為 text。 |
| --left-title text | 設(shè)置頁面左標(biāo)題為 text。 |
| --line-numbers=interval | 每隔 interval 行輸出行號。 |
| --list=defauls | 顯示默認(rèn)設(shè)置。 |
| --list=topic | 顯示 topic 設(shè)置,topic 表示下列之一:代理程序(用來轉(zhuǎn)換數(shù)據(jù)的外部程序),編碼,特征,變量,媒介(頁面大小等),ppd(PostScript 打印機(jī)描述信息),打印機(jī),起始程序(為常規(guī)輸出添加前綴的代碼部分),樣式表,或用戶選項(xiàng)。 |
| --pages range | 打印 range 范圍內(nèi)的頁面。 |
| --right-footer text | 設(shè)置右頁腳為 text。 |
| --right-title text | 設(shè)置頁面右標(biāo)題為 text。 |
| --rows number | 將所有頁面排列成 number 排。默認(rèn)為1。 |
| -B | 沒有頁眉。 |
| -b text | 設(shè)置頁眉為 text。 |
| -f size | 使用字體大小為 size 號。 |
| -l number | 設(shè)置每行字符數(shù)為 number。此項(xiàng)和 -L 選項(xiàng)(見下方)可以給文件用其他程序來更準(zhǔn)確的分頁,如 pr。 |
| -L number | 設(shè)置每頁行數(shù)為 number。 |
| -M name | 使用打印媒介的名稱——例如,A4。 |
| -n number | 每頁輸出 number 份。 |
| -o file | 輸出到文件 file。如果指定為 - ,則輸出到標(biāo)準(zhǔn)輸出。 |
| -P printer | 使用打印機(jī) printer。如果未指定,則使用系統(tǒng)默認(rèn)打印機(jī)。 |
| -R | 縱向打印。 |
| -r | 橫向打印。 |
| -T number | 設(shè)置制表位為每 number 字符。 |
| -u text | 用 text 作為頁面底圖(水?。?/td> |
以上只是對 a2ps 的總結(jié),更多的選項(xiàng)尚未列出。
注意:a2ps 目前仍在不斷的開發(fā)中。就我的測試而言,不同版本之間都多少有所變化。CentOS 4 中輸出總是默認(rèn)為標(biāo)準(zhǔn)輸出。在 CentOS 4 和 Fedora 10 中,盡管程序配置信紙為默認(rèn)媒介,輸出還是默認(rèn)為 A4紙。我可以明確的指定需要的選項(xiàng)來解決這些問題。Ubuntu 8.04 中,a2ps 表現(xiàn)的正如參考文檔中所述。 另外,我們也要注意到另一個(gè)轉(zhuǎn)換文本為 PostScript 的輸出格式化工具,名叫 enscript。它具有許多相同的格式化和打印功能,但和 a2ps 唯一的不同在于,它只能處理純文本的輸入。
由于 Unix 打印系統(tǒng)的設(shè)計(jì)是能夠處理多用戶的多重打印任務(wù),CUPS 也是如此設(shè)計(jì)的。每臺打印機(jī)都有一個(gè)打印隊(duì)列,其中的任務(wù)直到傳送到打印機(jī)才停下并進(jìn)行打印。CUPS 支持一些命令行程序來管理打印機(jī)狀態(tài)和打印隊(duì)列。想 lpr 和 lp 這樣的管理程序都是以 Berkeley 和 System V 打印系統(tǒng)的相應(yīng)程序?yàn)橐罁?jù)進(jìn)行排列的。
lpstat 程序可用于確定系統(tǒng)中打印機(jī)的名字和有效性。例如,我們系統(tǒng)中有一臺實(shí)體打印機(jī)(名叫 printer)和一臺 PDF 虛擬打印機(jī)(名叫 PDF),我們可以像這樣查看打印機(jī)狀態(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)默認(rèn)的打印機(jī),其本身是一臺網(wǎng)絡(luò)打印機(jī),使用網(wǎng)絡(luò)打印協(xié)議(ipp://)通過網(wǎng)絡(luò)連接到名為 print-server 的系統(tǒng)。
lpstat 的常用選項(xiàng)列于表23-5。
| 選項(xiàng) | 描述 |
|---|---|
| -a [printer...] | 顯示 printer 打印機(jī)的隊(duì)列。這里顯示的狀態(tài)是打印機(jī)隊(duì)列承受任務(wù)的能力,而不是實(shí)體打印機(jī)的狀態(tài)。若未指定打印機(jī),則顯示所有打印隊(duì)列。 |
| -d | 顯示系統(tǒng)默認(rèn)打印機(jī)的名稱。 |
| -p [printer...] | 顯示 printer 指定的打印機(jī)的狀態(tài)。若未指定打印機(jī),則顯示所有打印機(jī)狀態(tài)。 |
| -r | 顯示打印系統(tǒng)的狀態(tài)。 |
| -s | 顯示匯總狀態(tài)。 |
| -t | 顯示完整狀態(tài)報(bào)告。 |
使用 lpq 程序可以查看打印機(jī)隊(duì)列的狀態(tài),從中我們可以看到隊(duì)列的狀態(tài)和所包含的打印任務(wù)。下面的例子顯示了一臺名叫 printer 的系統(tǒng)默認(rèn)打印機(jī)包含一個(gè)空隊(duì)列的情況:
[me@linuxbox ~]$ lpq
printer is ready
no entries
如果我們不指定打印機(jī)(用 -P 參數(shù)),就會顯示系統(tǒng)默認(rèn)打印機(jī)。如果給打印機(jī)添加一項(xiàng)任務(wù)再查看隊(duì)列,我們就會看到下列結(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
CUPS 提供兩個(gè)程序來從打印隊(duì)列中終止并移除打印任務(wù)。一個(gè)是 Berkeley 風(fēng)格的(lprm),另一個(gè)是 System V 的(cancel)。在支持的選項(xiàng)上兩者有較小的區(qū)別但是功能卻幾乎相同。以上面的打印任務(wù)為例,我們可以像這樣終止并移除任務(wù):
[me@linuxbox ~]$ cancel 603
[me@linuxbox ~]$ lpq
printer is ready
no entries
每個(gè)命令都有選項(xiàng)可用于移除某用戶、某打印機(jī)或多個(gè)任務(wù)號的所有任務(wù),相應(yīng)的參考手冊中都有詳細(xì)的介紹。