简介:面向在 Linux 桌面或服务器环境中使用佳能打印机的用户与运维人员,这份资源提供基于 CUPS 架构的通用驱动包,用于解决发行版自带驱动缺失、打印机识别异常与打印队列无法管理等问题,适合具备基础 Linux 命令行操作能力的读者。压缩包共 195 个文件,约 16.48MB,以 icc 色彩配置文件、h 头文件与 c 源码、sh 安装脚本、so 动态库及 readme、changelog、po 多语言文件为主,另含 spec、rules、control 等打包与安装描述文件,兼顾编译、部署与文档查阅。目前已有 1095 人学习下载。借助包内的打印机描述文件与管理工具,读者可完成打印机添加、队列启停与状态查询,并通过 lpadmin、cupsenable、cupsdisable、lpstat 等命令排查常见打印故障;changelog 与 readme 也有助于判断驱动版本与内核、发行版的兼容性,减少反复试错成本。
1. 一台打印机在 Linux 上“消失”的三种死法:CUPS 驱动到底管什么
CUPS linux 驱动这几个词被一起搜,多半不是想研究打印原理,而是手边有台机器正处在三种死法之一:队列建好了但作业永远卡在 “Processing”、打出来整页乱码或整页黑、双面和纸盒选项在设置界面里灰掉根本不给你选。这三种症状指向的是三个完全不同的层——PPD 能力声明、filter 转换链、backend 传输通道。这份资源就是围绕 CUPS 的一套驱动包与配套调试方法:包含设备的能力描述文件、格式转换组件、传输后端以及安装脚本,解决的是“打印机在 Linux 桌面和服务器上被识别、被正确渲染、被稳定送达”这条链路。
它适合三类人:桌面 Linux 用户想把家里那台机器跑通;运维需要在一批机器上批量部署同一个打印队列;以及被厂商只提供闭源安装器、想搞清楚它到底往系统里写了什么的人。下面按“先拆包看结构,再命令行建队列,然后调参数,最后排错”的顺序走一遍,能抄的代码我都贴出来。
2. 拆开 CUPS 驱动包:PPD、filter、backend 三层各干什么
拿到一个厂商驱动包,第一反应不该是双击安装,而是先看它往系统里放什么。绝大多数 Linux 打印驱动包拆开之后只有四类东西:一个或多个 PPD 文件、若干放在 filter 目录的可执行转换程序、可能带一个私有 backend、外加一个安装脚本和几条 udev 规则。搞清楚这四类东西各自负责哪一段,后面所有排错都能定位到具体层,而不是笼统地“驱动没装好”。
我一般的习惯是先解包到临时目录,不做任何系统级安装,因为厂商的 setup 脚本经常顺手改/etc/cups/cupsd.conf、塞 udev 规则、甚至注册开机服务,这些副作用事后很难干净回滚。先看清楚再决定装不装,是省后悔药的最便宜做法。
# 解包不要直接装,先摊开看内容 mkdir -p /tmp/drv && cd /tmp/drv # Debian/Ubuntu 系 dpkg-deb -x ./vendor-printer-driver_1.0_amd64.deb ./extract # RHEL/openSUSE 系 rpm2cpio ./vendor-printer-driver-1.0.x86_64.rpm | cpio -idmv --no-absolute-filenames # 只列出文件路径,快速判断目录归属 find ./extract -type f | sed 's|^\./extract||' | sort这段命令的关键在最后一行:find输出的路径前缀直接告诉你文件的目标位置。看到/usr/share/ppd/就是能力描述,看到/usr/lib/cups/filter/就是转换程序,看到/usr/lib/cups/backend/就是传输后端。--no-absolute-filenames是必须带的,某些 rpm 里会打包绝对路径,不加这个参数 cpio 会直接往根目录写。
2.1 PPD 不是配置文件,是驱动的“能力声明”
很多人把 PPD 当成一份普通配置,改两个字段就想生效,结果发现改完不生效甚至队列起不来。PPD 的本质是 PostScript Printer Description,它描述的是一台设备“会什么”:支持哪些分辨率、有哪些纸盒、能不能双面、色彩模式有几种、每个选项对应什么 PostScript 或私有指令。CUPS 读它来生成打印对话框里的选项树,也读它来决定走哪条 filter 链。
一份 PPD 里真正影响能否打印的字段其实不多,看下面这几行就够了:
*NickName: "A Laser 2200 Foomatic/foo2xxx" *Manufacturer: "VendorA" *ModelName: "A Laser 2200" *DefaultResolution: 600dpi *Resolution 600dpi/600 dpi: "<</HWResolution[600 600]>>setpagedevice" *OpenUI *Duplex/Two-Sided: PickOne *Duplex None/Off: "<</Duplex false>>setpagedevice" *Duplex DuplexNoTumble/Long Edge: "<</Duplex true /Tumble false>>setpagedevice" *CloseUI: *Duplex *cupsFilter2: "application/pdf application/vnd.cups-raster 0 rastertoxxx"*cupsFilter2是判断这个 PPD 属于哪个语言家族的最快入口。它写成三段加一个成本值:源 MIME、目标 MIME、成本、调用的 filter 名。上面这行意味着 PDF 进来后交给rastertoxxx转成私有光栅格式。如果一行*cupsFilter2都没有,而是老的*cupsFilter,说明这份 PPD 年代偏早,转换链可能还是走 Ghostscript 中转,速度会慢一截。
*OpenUI/*CloseUI包起来的那一段是给界面用的选项组,*DefaultResolution、*DefaultPageSize决定默认值。想让默认双面打开,不是改 PPD 里的*Duplex,而是加一行*DefaultDuplex: DuplexNoTumble,或者更省事地在建队列时用lpadmin -o覆盖——PPD 是只读的“厂商声明”,运行期偏好放在队列属性里,两者别混。
提示:PPD 一旦被
lpadmin关联到队列,CUPS 会把它复制一份到/etc/cups/ppd/<队列名>.ppd。之后你改原始文件是没用的,改的是这份副本;想彻底重置,得先删队列再重建。
2.2 filter 链:从 PDF 到墨点的翻译流水线
filter 是整条链里最容易翻车的一层,因为它是二进制、报错信息少、还牵扯权限。CUPS 收到一个作业后,会按/etc/cups/mime.types和mime.convs里的规则,把这个作业的 MIME 类型一步步转换成打印机认识的类型。每一步转换就是一个 filter 进程,前一个的输出是后一个的输入,最后交给 backend 送出门。
转换路径不是唯一的,同一对源和目标可能有多条路径,CUPS 用“成本值”选最便宜的那条。成本 0 表示专用转换,成本 50 以上往往是靠 Ghostscript 兜底。所以同一个 PDF,走厂商私有 filter 和走通用光栅化的结果,出纸速度和画质会有肉眼可见的差别。这也是为什么有些机器装完能打但奇慢——它其实一直在走兜底路径。
调试这一层最有效的工具是cupsfilter,它可以脱离打印机、脱离队列,单独跑一遍转换并把结果写到文件:
# 用指定 PPD 把 PDF 转成 CUPS 光栅格式,看转换链能不能走通 cupsfilter -m application/vnd.cups-raster \ -p /etc/cups/ppd/A2200.ppd \ /tmp/test.pdf > /tmp/out.raster 2>/tmp/cupsfilter.err # 看退出码和错误输出 echo "exit=$?" tail -n 20 /tmp/cupsfilter.err-m指定目标 MIME,-p指定用哪份 PPD 的规则,重定向出来的文件大小是最直观的判据:正常的光栅文件应该是几 MB 到几十 MB,如果只有几百字节,说明转换提前失败了。2>把 stderr 单独收走很重要,cupsfilter的错误信息和正常的进度信息混在一起,不分离根本没法看。
filter 程序本身的权限是另一个高频坑。它们必须放在/usr/lib/cups/filter/(部分发行版是/usr/libexec/cups/filter/),属主 root、属组 lp、权限 755。有些驱动包解出来的文件是 644,CUPS 起子进程时直接 permission denied,而日志里只会给你一句含糊的 “Filter failed”。
# 统一修正常见的 filter 权限问题 chown root:lp /usr/lib/cups/filter/rastertoxxx chmod 755 /usr/lib/cups/filter/rastertoxxx # 开了 SELinux 的发行版还要确认上下文 restorecon -vR /usr/lib/cups/filter/ ls -Z /usr/lib/cups/filter/rastertoxxx2.3 backend 与设备 URI:数据从哪条路出门
backend 负责最后一公里,把 filter 产出的字节流送到设备。它和 URI 方案是一一对应的:usb://走 USB backend,socket://走裸 TCP,ipp://走 IPP,lpd://走老式 LPD。CUPS 自带一批 backend,位于/usr/lib/cups/backend/,注意这个目录里的可执行文件有一个特殊要求——必须带 setuid root 位,否则普通用户提交的作业没法打开 USB 设备或绑定低端口。
判断设备到底被哪条路看见,一条命令就够:
# 列出当前所有可用 backend 能发现的设备 lpinfo -v # 典型输出 # direct usb://VendorA/A%20Laser%202200?serial=0000A1B2 # network socket://192.168.1.50:9100 # network ipp://192.168.1.50:631/ipp/print # network dnssd://A%20Laser%202200._ipp._tcp.local/cups?uuid=...lpinfo -v里direct开头的是本地直连设备,network开头的是网络发现的。如果这里压根看不到你的机器,问题就不在 PPD、不在 filter,而是设备根本没暴露给 CUPS——USB 线、网段、防火墙、mDNS 任一处断了都会这样。反过来,如果这里能看到设备但打不出来,才轮到前面两层背锅。这个先分叉再排查的顺序,能省掉大量瞎试。
| URI 方案 | 对应 backend | 适用场景 | 注意点 |
|---|---|---|---|
usb:// | usb | 本地 USB 直连 | 需要 setuid 位,虚拟机需透传 |
socket://IP:9100 | socket | 网络机型裸端口打印 | 无状态回传,出错只能靠日志 |
ipp://IP:631/ipp/print | ipp | 支持 IPP 的网络机型 | 可回传状态和耗材信息 |
dnssd:// | dnssd | 局域网自动发现 | 依赖 avahi,跨网段常失效 |
lpd://IP/queue | lpd | 老式打印服务器 | 队列名写错会静默丢作业 |
3. 从零装通一台打印机:命令行的四步闭环
图形化的打印设置面板看起来友好,但它把关键参数都藏起来了,出问题时你连当前用的什么 URI、绑的哪份 PPD 都不知道。命令行建队列虽然多敲几行,但每一步的输入输出都是可见的,出问题能回溯。下面这套流程我在桌面和服务器上都用,四步走完一个队列就该是能出纸的状态。
3.1 让 CUPS 先“看见”设备:lpinfo 与 URI 拼装
第一步永远是确认设备可见,也就是上一节提到的lpinfo -v。如果设备在列表里,把那一行 URI 原样复制下来,不要手敲——URI 里的空格会被编码成%20,序列号、UUID 这些参数一个字符都不能错。手敲 URI 是新手最常见的失误来源。
网络机型如果lpinfo -v里什么都没有,先用最原始的办法验证连通性:
# 确认 9100 裸打印端口是否开放 nc -zv 192.168.1.50 9100 # 确认 IPP 端口 nc -zv 192.168.1.50 631 # 用 SNMP 探一下设备信息,很多机型会回传型号和页面计数 snmpwalk -v1 -c public 192.168.1.50 1.3.6.1.2.1.43.5.1.1.16nc -zv只做连接测试不发数据,-z是零 I/O 扫描模式,-v输出详细信息。9100 通、631 不通,说明这台机器只支持裸端口打印;两个都通,优先走 IPP,因为 IPP 能回传缺纸、卡纸、墨量这些状态,而 socket 是单向的哑管道。
至于驱动选哪份,用lpinfo -m列出系统当前认识的所有 PPD 与驱动:
# 列出所有可用驱动,按厂商关键字过滤 lpinfo -m | grep -i -E 'vendorA|laser' # 只看某个已安装驱动包提供的型号 lpinfo -m | grep -i 'a2200'-m输出的是驱动名/描述的形式,冒号前那串就是后面lpadmin -m要用的标识。如果这里搜不到你的型号,说明驱动包没装进 CUPS 的搜索路径,得回头把 PPD 放到/usr/share/ppd/或/usr/share/cups/model/下再重试。
3.2 用 lpadmin 建队列:-m、-P、-v 三个参数别搞混
建队列只有一条命令,但参数含义经常被搞混。-v是设备 URI,回答“送到哪”;-m是按驱动名选 PPD,-P是直接指定 PPD 文件路径,两者二选一,同时给会以后者为准;-E一次做两件事——启用队列并接受作业,等价于cupsenable加cupsaccept。少了-E,队列建出来是停用状态,作业会一直排队不动。
# 建一个网络打印机队列,用驱动名选 PPD lpadmin -p A2200 \ -v socket://192.168.1.50:9100 \ -m "vendorA-a2200-ps.ppd" \ -D "A Laser 2200 实验室" \ -L "3F-302" \ -o printer-is-shared=false \ -E # 建一个 USB 直连队列,直接指定 PPD 文件 lpadmin -p A2200USB \ -v "usb://VendorA/A%20Laser%202200?serial=0000A1B2" \ -P /usr/share/ppd/vendorA/a2200.ppd \ -E # 设置默认打印机 lpadmin -d A2200 # 确认队列状态 lpstat -p A2200 -l-p后面的队列名建议只用小写字母数字和连字符,带空格或中文的队列名在某些老版本客户端上会被截断。-D和-L是描述和位置,看着无关紧要,但机器一多,靠这两个字段才能在列表里认出谁是谁。-o printer-is-shared=false在桌面环境里建议显式加上,否则 CUPS 可能按默认策略把队列广播到局域网。
lpstat -p A2200 -l的输出要重点看三处:printer is idle还是disabled、Form mounted后面跟的纸型、以及最后几行的Interface路径。如果 Interface 指向/etc/cups/ppd/A2200.ppd,说明 PPD 已经被复制并生效了。
3.3 提交与验证:lp、lpstat、cancel 的最小闭环
队列是 idle 不等于能打印,必须真发一个作业验证到底。验证顺序最好是:纯文本 → 单页 PDF → 多页双面 PDF。纯文本走的是最简单的转换链,能打出来说明 backend 和基础 filter 没问题;再上 PDF 才能暴露 filter 链的问题;最后上多页双面才是压测。
# 第一步:纯文本冒烟测试 printf 'printer smoke test\nline2\n' > /tmp/smoke.txt lp -d A2200 -o media=A4 /tmp/smoke.txt # 第二步:单页 PDF lp -d A2200 -o media=A4 -o fit-to-page /tmp/one-page.pdf # 第三步:看作业队列和状态 lpstat -o A2200 lpstat -p A2200 -W completed # 出问题就撤掉全部作业,别让坏作业堆着 cancel -a A2200lp成功时只回一行request id is A2200-15 (1 file(s)),这行只代表作业进了队列,不代表打出来了。真正的判据是lpstat -o里这条作业消失,并且后续lpstat -p仍是 idle。如果作业长时间停在Processing -,八成卡在 filter;如果状态变成Stopped,直接用cancel -a清空再查日志,堆着不处理会让后续所有作业一起堵死。
-o fit-to-page这个选项值得单独提一句:PDF 页面尺寸和纸张尺寸不一致时,不加它内容会被裁切而不是缩放。A4 内容打到 Letter 纸上、或者反过来,都是这个原因。
3.4 网络机型的两条岔路:socket 9100 与 IPP Everywhere
网络打印机有两条路。一条是厂商私有语言走 socket 9100,必须配对应 PPD;另一条是走 IPP Everywhere(也叫 driverless),CUPS 直接用everywhere这个虚拟驱动,靠设备自己上报能力,完全不装厂商驱动。后者在支持 IPP 2.0 的机型上体验好得多,升级内核或换发行版都不用重新折腾驱动。
# 走 IPP Everywhere,不需要任何厂商 PPD lpadmin -p A2200IPP \ -v ipp://192.168.1.50:631/ipp/print \ -m everywhere \ -E # 先探测设备是否真的支持 driverless driverless ipp://192.168.1.50:631/ipp/print # 看它自动生成了哪些可选项 lpoptions -p A2200IPP -l-m everywhere是 CUPS 2.2 之后的内置虚拟驱动,driverless命令(部分发行版在driverless-ipp-utils包里)可以先探一下再决定。lpoptions -p 队列 -l会列出这个队列当前所有可设选项和取值,是判断“双面能不能用”“纸盒认没认出来”最快的手段。
两条路的取舍很明确:机器支持 IPP 2.0,优先 driverless,省驱动、省维护;机器只支持私有语言,才回到 socket 或 USB 配厂商 PPD。判断方法就是跑一次driverless,能输出 PPD 内容就说明支持。
| 对比项 | socket://IP:9100 | ipp://IP:631/ipp/print + everywhere |
|---|---|---|
| 是否需要厂商驱动 | 需要 | 不需要 |
| 状态回传 | 无 | 有(缺纸、卡纸、耗材) |
| 双面/纸盒选项 | 依赖 PPD 声明 | 设备自动上报 |
| 跨网段可用性 | 好 | 好(但发现靠手动填 IP) |
| 故障定位难度 | 高,只能看日志 | 低,lpstat -l能看到原因 |
4. 参数怎么调:分辨率、色彩、纸张与双面打印的实际取舍
队列通了只是及格线,真正决定好不好用的是后面这几个参数。CUPS 的参数有三个来源,优先级从高到低是:lp命令行的-o、队列默认属性(lpadmin -o设的)、PPD 里的*Default*。搞清楚这个优先级,就不会出现“我明明改了 PPD 怎么没用”的困惑。查当前生效值用lpoptions -p <队列> -l,改队列默认值用lpadmin -p <队列> -o 选项=值。
4.1 分辨率与半色调:600dpi 够不够
分辨率不是越高越好,这话在激光机上尤其成立。600dpi 的 A4 单页光栅数据大约 8MB 上下,1200dpi 直接翻四倍到 30MB 以上,而这四倍数据量带来的是传输时间、filter 处理时间、打印机内存占用的全面上涨,肉眼能分辨的清晰度提升却很有限——除非你打的是细线条图纸或者 6pt 小字。
# 单次作业指定分辨率 lp -d A2200 -o Resolution=600dpi /tmp/doc.pdf # 把 600dpi 设为该队列的默认值 lpadmin -p A2200 -o Resolution=600dpi # 查看 PPD 声明了哪些分辨率可选 grep -E '^\*Resolution' /etc/cups/ppd/A2200.ppdResolution这个选项名不是硬性标准,不同 PPD 里可能写成Resolution、SetResolution或厂商自定义名。所以第一步永远是lpoptions -l看实际有哪些,而不是照着别人的命令抄。抄错了 CUPS 不会报错,只会静默忽略这个选项,然后你对着没变化的输出困惑半天。
半色调(halftoning)是另一个容易被忽略的点。灰度图和照片类内容在二值激光机上必须经过抖动处理,处理方式不同,出来的颗粒感差别很大。部分 PPD 会暴露Halftone或Dither选项,取值通常是Fine、Coarse、ErrorDiffusion之类。打文字用细网点,打图片用误差扩散,这个组合我试下来最稳。
4.2 色彩模式、灰度与墨量
彩色机型在 Linux 下的色彩管理是个黑匣子,因为厂商的 ICC 配置基本只随 Windows 驱动发布。CUPS 这条链上能控制的只有色彩空间和模式,管不到精细的色彩校准。务实的做法是:文档类内容强制灰度,需要彩色的场合接受“够用就好”,别指望和原厂 Windows 驱动逐像素一致。
# 强制灰度打印,省彩墨也避免偏色 lp -d A2200 -o ColorModel=Gray /tmp/report.pdf # 彩色模式下指定色彩空间,部分 PPD 支持 lp -d A2200 -o ColorModel=CMYK -o ColorSpace=DeviceRGB /tmp/pic.pdf # 草稿模式:降低墨量,速度明显变快 lp -d A2200 -o print-quality=3 /tmp/draft.pdfprint-quality是 IPP 标准属性,取值 3/4/5 分别对应草稿/正常/高质量,比厂商自定义的Quality选项通用性更好。ColorModel的取值要看 PPD,常见是Gray、RGB、CMYK。如果lpoptions -l里压根没有ColorModel,说明这份 PPD 没声明色彩选项,只能靠-o传厂商私有键值,具体键名得翻 PPD 的*OpenUI段。
4.3 纸张、边距、双面与纸盒选择
纸张相关的参数是日常用得最多的,也是选项名最不统一的。media是 IPP 标准名,取值形如A4、na_letter、A4.FullBleed;双面是sides,取值one-sided、two-sided-long-edge、two-sided-short-edge;纸盒是InputSlot或MediaSource,取值因机器而异,常见Auto、Tray1、Manual。
# 双面长边翻转 + A4 + 从纸盒1进纸 lp -d A2200 \ -o media=A4 \ -o sides=two-sided-long-edge \ -o InputSlot=Tray1 \ /tmp/manual.pdf # 多页合一,省纸场景常用 lp -d A2200 -o number-up=2 -o media=A4 /tmp/slides.pdf # 手动进纸打信封 lp -d A2200 -o media=DL -o InputSlot=Manual /tmp/letter.pdftwo-sided-long-edge和two-sided-short-edge的区别是装订边:长边翻转适合纵向文档,翻页方向像翻书;短边翻转适合横向内容,翻页方向像翻台历。选错了内容会上下颠倒,这个错误在双面打印里出现频率极高,而且很多人第一反应是驱动有问题。
| 常用选项 | 典型取值 | 说明 |
|---|---|---|
media | A4、na_letter、DL | IPP 标准纸型名,别用中文纸型 |
sides | one-sided、two-sided-long-edge | 双面方向按装订边选 |
InputSlot | Auto、Tray1、Manual | 名称随 PPD 变化,先lpoptions -l |
number-up | 1、2、4 | 多页合一,由 CUPS 侧合成 |
fit-to-page | 布尔,无值 | PDF 与纸张尺寸不符时必加 |
print-quality | 3、4、5 | 草稿/正常/高质量 |
还有一个坑是“不可打印边距”。打印机物理上打不到纸张最外圈,典型激光机四边各 4mm 左右。CUPS 默认不会帮你缩进内容,超出部分直接丢。需要满幅效果时,要么用-o page-left=... page-right=...手动设边距,要么在设计文档时就留出安全区。指望驱动自动处理,多半会失望。
5. 避坑与排查:五条血泪记录
前面三章讲的是“应该怎么装”,这一章讲“装完不对怎么办”。打印这条链路的特殊性在于:错误几乎都被吞掉了。CUPS 的设计哲学是尽量让作业成功,所以它会在失败时悄悄降级、悄悄重试、悄悄换条路径,你看到的往往只是一个卡住不动的队列。学会看日志、学会分层定位,比记住任何一条命令都重要。
5.1 队列能建但作业永远停在 Processing
现象:lp提交成功,lpstat -o里作业一直显示Processing -,几十分钟不动,也不报错,打印机毫无反应。
原因:卡在 filter 层。最典型的是 filter 程序权限不对(缺执行位或属组不是 lp),其次是 filter 依赖的动态库缺失,再其次是 PPD 里*cupsFilter2指向的文件名和实际放在 filter 目录里的文件名对不上——厂商打包时改名是常事。
解决:把日志级别开到 debug 再复现一次,日志会明确告诉你它试图执行哪个 filter、失败原因是什么。
# 临时开 debug 日志 cupsctl --debug-logging # 提交一个作业 lp -d A2200 /tmp/smoke.txt # 实时跟踪日志,关注 filter 相关行 tail -f /var/log/cups/error_log | grep -Ei 'filter|exec|permission|No such' # 排查完记得关掉,debug 日志涨得很快 cupsctl --no-debug-logging日志里出现Unable to execute /usr/lib/cups/filter/xxx: Permission denied就是权限问题,出现No such file or directory就是文件名对不上。对着修完再打一次,通常一次就通。
5.2 打出整页黑、整页白或满纸乱码
现象:作业状态正常走完,纸也出了,但内容是整页黑、整页空白,或者一堆看不懂的字符。
原因:整页黑基本是数据格式和打印机语言不匹配——把光栅数据当成 PostScript 送了,或者反过来。整页白多半是 filter 链跑完但输出为空,常见于 PDF 里字体嵌入异常。乱码则是 PPD 声明的页面描述语言和机器实际支持的语言不一致,这类问题在“一个系列多个型号共用一份 PPD”的驱动包里特别常见。
解决:先用cupsfilter单独跑一遍转换,确认输出文件大小正常;再确认 PPD 里*NickName和*ModelName是否精确匹配你的型号。型号差一个后缀,用的可能就是完全不同的语言。
# 单独验证转换链,输出文件异常小就是转换失败 cupsfilter -m application/vnd.cups-raster \ -p /etc/cups/ppd/A2200.ppd \ /tmp/one-page.pdf > /tmp/check.raster 2>/tmp/check.err ls -lh /tmp/check.raster tail -n 30 /tmp/check.err如果check.raster只有几百字节,问题在 filter;如果它有几十 MB 但打出来仍是乱码,问题在 PPD 选错型号,换一份精确匹配的 PPD 重试。
5.3 双面和纸盒选项在界面上是灰的
现象:打印对话框里双面选项不可选,或者纸盒下拉框只有一个 Auto。
原因:PPD 没声明这些能力,或者声明了但*OpenUI/*CloseUI没配对。还有一种情况是驱动包里的 PPD 是“基础版”,双面单元作为选配件需要另一份 PPD 才启用。
解决:直接查 PPD 里有没有对应字段,以及运行期能不能用-o强传。
# 查 PPD 是否声明了双面能力 grep -A5 'OpenUI \*Duplex' /etc/cups/ppd/A2200.ppd # 如果声明了,命令行强制传值试探是否真支持 lp -d A2200 -o Duplex=DuplexNoTumble /tmp/manual.pdf # 列当前队列全部可选项,确认选项名拼写 lpoptions -p A2200 -l命令行能传通但界面灰,说明是界面读取 PPD 的问题;命令行也报Unknown option,说明这份 PPD 就是没这个能力,得换 PPD 而不是继续调参数。
5.4 重启后队列消失或打印服务起不来
现象:装好能用,机器重启之后队列不见了,或者systemctl status cups直接失败。
原因:/etc/cups/printers.conf没写盘,或者被别的程序覆盖了。部分厂商的安装脚本会在启动时重新生成配置,把手工建的队列冲掉。另一种可能是/etc/cups/目录权限被改坏,cupsd 读不了配置就拒绝启动。
解决:先看服务状态和配置文件的修改时间,再决定是重建队列还是修权限。
# 服务状态和最近日志 systemctl status cups --no-pager journalctl -u cups -n 50 --no-pager # 检查配置目录权限,正常应为 root:lp 755 ls -ld /etc/cups /etc/cups/ppd ls -l /etc/cups/printers.conf # 配置损坏时先备份再重建队列 cp /etc/cups/printers.conf /root/printers.conf.bak/etc/cups/printers.conf属主应为 root、属组 lp、权限 600。这个文件里存的是队列的 URI 和 PPD 引用,重建队列时它会被重写,所以改之前一定备份。
5.5 同一台机器不同用户打印结果不一致
现象:A 用户打出来正常,B 用户打出来是乱码或者打不出来。
原因:CUPS 的作业是按用户提交的,PPD 是全局共享的,但用户的~/.cups/lpoptions会覆盖队列默认值。某个用户之前用lpoptions设过Resolution=1200dpi或改过media,就会一直生效,而且这个设置不体现在任何全局配置里。
解决:检查用户级配置,必要时清掉。
# 看当前用户的覆盖项 lpoptions -p A2200 # 清空当前用户的打印偏好 rm -f ~/.cups/lpoptions # 以指定用户身份验证 sudo -u userb lpoptions -p A2200~/.cups/lpoptions是个纯粹的“后悔药缺失”现场——它存在感极低,却能解释一切“同一个队列别人能打我不能打”的玄学。交代给同事之前,先让他删一遍这个文件。
6. 进阶:把队列配置固化成可复现的脚本
手工敲命令建队列,一次两次还行,机器一多就会漏参数。我现在的做法是把整条建队列逻辑写成一个带幂等判断的脚本,重复执行不会报错,换台机器直接跑。核心思路是:先删同名队列(不存在就忽略),再按固定参数重建,最后跑一次冒烟测试。
#!/usr/bin/env bash set -euo pipefail QUEUE="A2200" URI="ipp://192.168.1.50:631/ipp/print" DESC="A Laser 2200 实验室" # 幂等:存在就先删,删除失败不阻断 lpadmin -x "$QUEUE" 2>/dev/null || true # 建队列并一次性设好默认参数 lpadmin -p "$QUEUE" -v "$URI" -m everywhere -D "$DESC" \ -o media=A4 \ -o sides=two-sided-long-edge \ -o print-quality=4 \ -E lpadmin -d "$QUEUE" # 冒烟测试:提交后等作业消失,超时则判定失败 printf 'smoke\n' > /tmp/smoke.txt JOB_ID=$(lp -d "$QUEUE" /tmp/smoke.txt | awk '{print $4}') for i in $(seq 1 30); do lpstat -o "$QUEUE" | grep -q "$JOB_ID" || { echo "OK: $JOB_ID done"; exit 0; } sleep 2 done echo "FAILED: $JOB_ID still queued" >&2 tail -n 40 /var/log/cups/error_log >&2 exit 1set -euo pipefail让脚本在任何一步失败时立刻退出,避免“前面错了后面还在跑”造成的假成功。lpadmin -x ... || true是幂等的关键,队列不存在时-x返回非零,被|| true吃掉。冒烟测试那段用awk从lp的输出里抠出作业 ID,再轮询lpstat -o等它消失,30 次 × 2 秒共 60 秒超时,够大部分单页作业跑完。超时后把日志尾巴打出来,省去再登录一次机器的时间。
三个容易忽略的细节:-m everywhere的队列在设备固件升级后能力可能变化,建议每月重跑一次lpoptions -l做对比;-o参数写得越多,新机器上不兼容的概率越高,非必要项别预设;脚本里不要硬编码 IP,抽成变量放在开头,换环境只改一行。
从那以后我每次给新机器建队列,都强制先跑一遍lpinfo -v和driverless两条探测命令再动手,绝不上来就装驱动包——因为真正的故障往往在“设备到底暴露了哪条路”这一层,而不是驱动本身。希望帮到你。
本文还有配套的精品资源,点击获取