在命令行里学习了这么久,我们处理了各种各样的文本。现在,是时候把这些文字变成白纸黑字了。 这一部分,我们将来学习如何在命令行里打印文件,以及如何管理我们的打印机。 我们不会涉及如何安装和配置打印机,因为这些步骤在不同的Linux发行版上差异很大,而且通常在系统安装时就已经自动设置好了。

要学习本部分的知识,你需要一台已经配置好并且可以正常工作的打印机。如果你的系统支持“打印到PDF”的功能,那会是一个非常方便的实验工具。
要真正理解Linux下的打印命令,我们得先来一次“穿越”,回到计算机的“石器时代”,看看打印机是如何一步步发展到今天的。这趟旅程能帮助我们明白,为什么有些命令看起来有点“老派”,但却依然强大。
想象一下早期的计算机,它们更像是庞大的、集中管理的巨兽。与它们配套的打印机也一样,昂贵、笨重,并且由专门的操作员看管。 在那个年代,很多用户需要共享一台打印机。为了区分谁打印了什么,每份打印任务的开头都会打印一张“横幅页”,上面写着用户名,就像是给文件贴上名牌。然 后,运维人员会推着小车,把一天打印出来的文件分发到每个人的办公桌上。
那时的打印机,更像是一台高速的自动打字机。它们使用的技术,比如“菊花轮打印”或“点阵打印”,都是通过物理撞击把墨水印在纸上。 更关键的是,这些打印机只能打印设备自身固有的一套字符,就像打字机上的铅字一样,每个字符的宽度都是固定的,我们称之为“等宽字体”。 这带来一个很有趣的结果:一张标准的信纸,在当时的技术下,大约能打印85个字符宽,66行高。为了留出边距,大家普遍认为一行打印80个字符是极限。 这个“80字符”的传统,一直流传到今天,这就是为什么我们的终端窗口默认宽度常常是80个字符。它提供了一种“所见即所得”的体验,你在屏幕上看到的,就约等于打印出来的样子。
数据传输给这种“打字机式”的打印机很简单,就是一连串的字节流。比如要打印一个'a',就发送它的ASCII码97。同时,还会发送一些控制码,比如回车、换行,来控制打印头的位置。 我们甚至可以用一些小技巧来实现粗体效果,比如打印一个字符,然后退格,再打印一遍,这样印出来的字迹就更深了。
随着图形用户界面(GUI)的出现,一切都变了。计算机屏幕变得五彩繽紛,能显示各种图片和字体,人们自然也希望打印机能做到同样的事情。低成本激光打印机的出现,让这一切成为了可能。 激光打印机不再是机械地敲打字符,而是像一位数字艺术家,用微小的墨点在纸上“画”出整个页面。这使得打印各种比例的字体、精美的图表甚至照片都成为了现实。
然而,从“打字机”到“艺术家”的转变,也带来了一个巨大的技术挑战。我们来算一笔账:
60 * 80 = 4800 字节的数据。(8 * 300) * (10 * 300) / 8 ≈ 900,000 字节,差不多1MB!在那个网络速度还很慢的年代,传输这么大的数据量去打印一页纸,是完全无法接受的。一个聪明的发明应运而生,那就是“页面描述语言”(Page Description Language, PDL)。
PDL本身就是一种编程语言,它不再描述页面上每个点是什么颜色,而是用指令来描述页面的内容。比如,“移动到这个坐标,用10号的Helvetica字体画一个'a'……”等等。 其中最著名的就是Adobe公司的PostScript。PostScript非常强大,它内置了对高质量字体的支持,还能在运行时接受新的字体定义。
最早,PostScript解释器是内置在打印机里的。打印机本身就像一台小电脑,接收PostScript程序,然后在自己的内存里把它“渲染”成最终要打印到纸上的点阵图像。 这个过程,我们称之为“光栅图像处理”(Raster Image Processor, RIP)。这样做的好处是,需要传输的PostScript程序文件,虽然比纯文本要大,但远小于渲染后的整个页面图像数据。
随着时间的推移,个人电脑和网络速度都飞速发展。于是,RIP这个过程就从昂贵的打印机硬件,转移到了我们的电脑软件上。 这也使得高质量的打印机变得越来越便宜。如今,很多打印机依然能处理简单的文本流,但更多低成本的打印机则完全依赖电脑上的RIP来提供最终的点阵图像。
了解了打印机的“前世今生”后,我们来看看现代Linux系统是如何驾驭这些打印机的。它主要依赖两位“大功臣”:CUPS 和 Ghostscript。
你可以把 CUPS (Common Unix Printing System,通用Unix打印系统) 想象成一位尽职尽责的“打印大管家”。在多用户的Unix世界里,打印机就像一个公共资源,大家都想用。如果没有人管理,场面肯定会一片混乱。CUPS就是这位管家,它负责接收所有人的打印请求,然后把这些任务放进一个“等待队列”里,一个接一个地安排给打印机处理,确保一切井井有条。CUPS还很智能,它能识别不同的文件类型(比如PDF、图片、文本文件),并自动调用合适的工具将它们转换成打印机能够理解的格式。
另一位功臣是 Ghostscript,它是一位专业的“PostScript翻译官”。还记得我们之前提到的页面描述语言PostScript吗?Ghostscript的作用,就是在我们的电脑上扮演那个“光栅图像处理器”(RIP)的角色。它读取PostScript文件里那些“画图指令”,然后将它们“翻译”成一张巨大的、由点组成的位图。这张位图精确地描绘了最终页面上的每一个细节,打印机拿到后,就可以直接把它印到纸上了。
所以,在Linux上,一次典型的打印流程是这样的:你提交一个打印任务,CUPS这位“管家”先接过来,如果文件需要转换(比如从一个文本文档转成打印格式),CUPS就会请Ghostscript这位“翻译官”出马,最后再把翻译好的内容交给打印机。
在命令行里打印,通常遵循一个清晰的流程:首先整理你的文本内容,让它在纸上看起来更美观;然后将它发送给打印机;如果需要,还可以使用更高级的工具进行专业级的排版。我们来一步步看。
在我们将文件送去打印之前,最好先把它整理一下,让它在A4纸上显得整洁有序。pr 命令就是为此而生的。你可以把它看作一个命令行的简易排版工具。它最擅长的是将长长的文本流分割成一页一页,并自动在每页的顶部加上页眉,通常包含文件名、日期和页码。
pr 本身并不执行打印操作,它只是一个“过滤器”,接收文本,处理后,再把结果输出出来。它最常和其它命令组合使用。
举个例子,/usr/bin 目录下通常有很多文件,如果我们直接用 ls 查看,会是一长串滚动的列表。现在我们想把它打印出来,并且希望是整洁的三栏格式。这时 pr 就派上用场了:
|$ ls /usr/bin | pr -3 -w 65
在这个例子里,ls /usr/bin 的输出通过管道 | 交给了 pr。-3 参数告诉 pr 把内容分成三栏,-w 65 则是设定页面的宽度为65个字符,以适应多栏布局。经过 pr 这么一“梳妆打扮”,输出的内容就变得非常适合阅读了。
排版好了,下一步就是把内容真正地发送到打印机了。在Linux世界里,有两个通用的命令来完成这项任务,它们分别来自Unix的两大历史分支:lpr (源自 Berkeley 分支) 和 lp (源自 System V 分支)。它们的功能大同小异,你可以根据自己的喜好选择一个。
我们继续上面的例子。现在想把排版好的三栏列表打印出来,只需要再加一个管道,把结果送给 lpr 即可:
|$ ls /usr/bin | pr -3 -w 65 | lpr
执行这个命令后,任务就被发送到你系统的“默认打印机”了。如果你有多台打印机,比如一台叫 laser_printer,另一台叫 inkjet_printer,你可以用 -P (大写的P) 参数来指定用哪一台:
|$ ls /usr/bin | pr -3 -w 65 | lpr -P laser_printer
lp 命令的用法也类似,只是指定打印机的参数换成了 -d (destination)。下面这个命令和上面那个 lpr 的例子是等效的:
|$ ls /usr/bin | pr -3 -w 65 | lp -d laser_printer
lp 还提供了一些其它实用的选项,比如 -n 可以指定打印的份数,-o (option)可以传递一些高级设置,比如横向打印:
|$ cat report.txt | lp -d laser_printer -n 3 -o landscape
这个命令会把 report.txt 文件在 laser_printer 上横向打印3份。
如果你对 pr 的简单排版不满意,想要更专业、更精美的输出,那么 a2ps 就是你的不二之选。a2ps 的名字最初是 “ASCII to PostScript” 的缩写,意味着它能把纯文本转换成高质量的PostScript文件。发展到今天,它的能力已经远不止于此,号称能 “Anything to PostScript”,也就是“万物皆可转PostScript”。
a2ps 不仅是个格式转换器,它本身也是一个强大的打印程序。它最擅长的是“美化打印”(pretty print)。它会自动为你的代码或文本加上漂亮的页眉页脚,甚至能把代码进行语法高亮,打印出来的效果非常专业。
它的一个常见用法是“多合一”打印,比如把两页的内容打印到一张A4纸上,以节约用纸。我们还是用 ls 的例子,这次让 a2ps 来处理,并让它输出到一个文件里,而不是直接打印:
|$ ls /usr/bin | a2ps -o ~/Desktop/ls.ps
执行后,你会在桌面上找到一个 ls.ps 文件。用文档查看器打开它,你会发现 a2ps 已经帮你把列表分成了两栏,并加上了精致的边框和页眉。如果你不使用 -o 参数,a2ps 就会像 lpr 一样,把美化后的结果直接发送给默认打印机。
a2ps 有着极其丰富的选项,比如你可以用 --center-title="My Directory Listing" 来设定标题,或者用 --line-numbers=5 来给文本加上行号,非常灵活。
想象一个场景:你刚刚把一份100页的论文发送到了打印机,按下回车键后,你突然惊出一身冷汗——你发错了版本!别担心,只要动作够快,我们还有机会“反悔”。命令行提供了一套工具,让我们能像管理员一样,查看和控制打印队列。
当你把一个打印任务发送给CUPS这位“大管家”后,它会把任务放进一个等待队列里。我们可以用 lpq 命令来查看这个队列的实时状态。这就像是查看游乐园里某个热门项目的排队情况。
如果你在一个空闲的打印机上执行 lpq,它会告诉你打印机已就绪,无事可做。但如果我们刚发送了一个任务,情况就不一样了:
|$ ls -R /etc | pr -2 | lpr request id is printer-603 (1 file(s))
我们刚刚提交了一个打印任务,系统告诉我们任务ID是 printer-603。现在,我们立刻用 lpq 查看:
|$ lpq printer is ready and printing Rank Owner Job File(s) Total Size active jules 603 (stdin) 1024 bytes
看,我们的任务正在队列里!Rank 是 active,表示它正在被打印。Owner 是用户名,Job 就是我们至关重要的“任务ID”(603)。有了这个ID,我们就能进行下一步操作了。
找到了错误的打印任务,现在我们要把它从队列里“揪出来”。和发送打印一样,取消任务也有两个命令:lprm (Berkeley风格) 和 cancel (System V风格)。它们的作用完全相同。
我们使用刚刚得到的任务ID 603 来取消任务:
|$ cancel 603
或者使用 lprm:
|$ lprm 603
执行命令后,CUPS会立即停止处理这个任务,并将其从队列中移除。如果我们再用 lpq 查看,就会发现队列又变空了,成功避免了浪费纸张。
lpq 专注于显示某个打印队列里的任务,而 lpstat 则提供了更全面的状态报告。它能告诉你系统里有哪些打印机、它们的状态如何,以及默认的打印机是哪一台。
比如,用 lpstat -a 可以查看所有打印机是否正在接受新的打印任务:
|$ lpstat -a PDF accepting requests since Mon Dec 8 15:05:59 2008 laserjet accepting requests since Tue Feb 24 08:43:22 2009
这表示我们有一台名为 PDF 的虚拟打印机和一台名为 laserjet 的实体打印机,它们都处于可用状态。
如果你想知道哪台是默认打印机?可以用 -d 参数:
|$ lpstat -d system default destination: laserjet
这条信息告诉我们,如果我们执行 lpr 或 lp 时不指定打印机,任务会自动发送到 laserjet。
在这一部分,我们从打印机的“远古时代”一路走来,了解了它的技术演变如何塑造了我们今天在Linux上使用的打印命令。
我们认识了CUPS这位“打印大管家”和Ghostscript这位“翻译官”,并掌握了从格式化(pr)、发送(lpr, lp)、美化(a2ps)到最后管理(lpq, lprm, lpstat)的整个命令行打印流程。
虽然现在我们更多地在图形界面中点击“打印”按钮,但了解这些背后的命令,不仅能让我们在没有图形界面时也能轻松打印,更能让我们对系统的工作原理有更深刻的理解。