11. 命令行
← 标准库 · 目录 · 下一章:实用范例 →
共 12 个命令:4 个处理 PDF,4 个处理脚本,2 个用于分发,2 个用于许可证。
| 命令 | 功能 |
|---|---|
run |
用脚本校验 PDF |
compare |
比较两个版本 |
watch |
监视文件夹并校验新到的文件 |
fix |
应用修改并保存新的 PDF |
inspect |
快速查看 PDF 概要 |
lint |
不执行地分析脚本 |
fmt |
格式化脚本 |
doc |
由脚本生成文档 |
pack |
打包配置与数据 |
add |
安装软件包 |
fingerprint |
设备指纹 |
license |
许可证校验 |
退出码
所有执行校验的命令都遵循同一约定。
| 代码 | 含义 |
|---|---|
0 |
全部通过 |
1 |
仅有警告 |
2 |
校验错误,或 PDF 无法读取 |
3 |
脚本语法错误 |
pdfl run profile.pdfl file.pdf > report.json
case $? in
0) echo "approved" ;;
1) echo "approved with warnings" ;;
2) echo "rejected — see report.json" ;;
3) echo "error in the validation script" ;;
esac
pdfl run
用脚本校验 PDF。
pdfl run <script.pdfl> <input.pdf> [options]
| 选项 | 默认 | 功能 |
|---|---|---|
--output json|csv|html|pdf |
json |
报告格式 |
--output-file <file> |
— | 写入文件而非标准输出 |
--fail-on error|warning |
error |
设为 warning 时警告也退出码 2 |
--verbose |
— | 标准错误输出附加信息 |
pdfl run prepress.pdfl magazine.pdf # 终端 JSON
pdfl run prepress.pdfl magazine.pdf --output html --output-file report.html
pdfl run prepress.pdfl magazine.pdf --output pdf --output-file report.pdf
pdfl run prepress.pdfl magazine.pdf --output csv --output-file findings.csv
pdfl run prepress.pdfl magazine.pdf --fail-on warning # 严格模式
JSON 报告
{
"script_name": "prepress.pdfl",
"input_file": "magazine.pdf",
"profile": "offset-magazine",
"status": "FAIL",
"total_pages_analyzed": 120,
"error_count": 2,
"warning_count": 0,
"info_count": 0,
"diagnostics": [
{
"id": "PDFL-001",
"severity": "error",
"check_name": "Ink coverage",
"message": "page 7: 324% ink (limit 300%)",
"line": 12
}
]
}
同一个 PDF 配同一个脚本,总是产生逐字节相同的报告,可用于版本管理和 CI 中的差异比对。
pdfl compare
比较两个版本:文本、结构和元数据。
pdfl compare <v1.pdf> <v2.pdf> [options]
| 选项 | 默认 | 功能 |
|---|---|---|
--output json|csv|html|pdf |
json |
格式 |
--output-file <file> |
— | 写入文件 |
--normalize |
— | 忽略大小写和空白 |
--ignore-dates |
— | 比较前遮蔽日期 |
--similarity-threshold <0-100> |
100 |
可接受的最低相似度 |
pdfl compare approved_v1.pdf new_v2.pdf --normalize --ignore-dates
# 允许 1% 以内的差异,低于该值即为错误
pdfl compare v1.pdf v2.pdf --similarity-threshold 99 \
--output html --output-file diff.html
工作原理
- 页面按内容而非页码对齐:中间插入了一页时,不会把其后的全部页面都报为 差异。可处理超过一千页的文档。
- 每个对齐的页面都会得到相似度分数,以及变化行的样本(
-删除、+新增)。 - 元数据变化记为警告;文本变化低于阈值记为错误,高于阈值记为警告。
- 报告中的
similarity字段给出总体分数。
page 4 → 4: similarity 97.8% | -original title | +revised title
pdfl watch
监视文件夹,校验每一个新到或被修改的 PDF。
pdfl watch <folder> --script <script.pdfl> [options]
| 选项 | 默认 | 功能 |
|---|---|---|
--pattern <glob> |
*.pdf |
处理哪些文件 |
--exclude <glob> |
— | 排除哪些文件 |
--output-dir <folder> |
与 PDF 同目录 | 报告输出位置 |
--depth <n> |
1 |
子目录深度 |
--debounce <ms> |
1000 |
等待文件稳定的时间 |
--report json|csv|html|pdf |
json |
报告格式 |
--fail-fast |
— | 遇到第一个错误即停止 |
--once |
— | 处理现有文件后退出 |
# 印刷厂的收件夹,持续运行
pdfl watch inbox/ --script preflight.pdfl --output-dir reports/ --report html
# CI 的批处理:处理完毕后以最差的退出码退出
pdfl watch inbox/ --script preflight.pdfl --once
echo "result: $?"
debounce 的存在是因为大文件是逐步写入的:只有文件不再变化才处理, 因此不会读到写了一半的 PDF。
报告写为 <name>.report.json(或 .csv、.html、.pdf)。
pdfl fix
应用 fix:: 操作并保存新的 PDF。详见第 8 章。
pdfl fix original.pdf normalize.pdfl --output out.pdf --dry-run # 只看会做什么
pdfl fix original.pdf normalize.pdfl --output fixed.pdf # 实际执行
pdfl inspect
无需脚本,快速查看 PDF 概要。
pdfl inspect <file.pdf>
File: magazine.pdf
Size: 26 KB (27284713 bytes)
SHA-256: af1029842e5bfeae338ead82fb449ef851be742b1d63117c12596e3ea123a616
Pages: 120
Page size: 496 x 709 pt
Boxes: MediaBox, TrimBox, BleedBox
Metadata:
Title: Example Magazine
Creator: Adobe InDesign 19.3
Fonts: 26
ABCDEF+Helvetica — embedded
Arial — NOT embedded
Images: 81 (minimum DPI 136, spaces: DeviceCMYK, Indexed)
Max. estimated TAC: 300% (RGB render approximation)
Warnings:
! there are non-embedded fonts
! 3 image(s) below 300 DPI
新文件到达时第一个该运行的命令:几秒钟就能判断是否值得打开。
pdfl lint
不执行脚本,分析并报告质量问题。
pdfl lint <script.pdfl>
检出内容:
- 声明后从未使用的变量、块参数和函数(加前缀
_可抑制:_page) - 重复或空的 check
- 未知的命名空间(
text::、struct::、visual::、prepress::、codes::、fix::、data::) - 位于 check 之外的
assert/require - 使用了
fix::(只能在pdfl fix中运行)
$ pdfl lint profile.pdfl
profile.pdfl: warning: variable 'LIMIT' declared and never used
profile.pdfl: warning: check "Fonts" declared 2 times
存在警告时退出码为 1,可用于 CI。
pdfl fmt
格式化脚本:两个空格缩进、统一空白、压缩空行。注释和单位(3mm 仍为 3mm)
都会保留。
pdfl fmt <script.pdfl> # 原地格式化
pdfl fmt <script.pdfl> --check # 不改动;未格式化时退出码 1
# 在 CI 中强制团队规范
for f in profiles/*.pdfl; do pdfl fmt "$f" --check || exit 1; done
pdfl doc
由脚本自身生成文档。
pdfl doc <script.pdfl> [--output markdown|html]
输出内容:配置名、常量表、函数、import,以及每个 check 的标签和校验内容
(assert 的消息成为说明)。
pdfl doc prepress.pdfl > docs/prepress-profile.md
pdfl doc prepress.pdfl --output html > profile.html
这是让不读代码的生产管理者了解配置在校验什么的交付物。
pdfl pack
把脚本和数据打包成可分发的 .pdflpkg。
pdfl pack <folder> [--name <name>] [--version <version>] [--output <file>]
递归收集文件夹中的 .pdfl、.csv、.txt、.json、.xlsx,并附带记录了
各文件 SHA-256 的 manifest.json。打包是确定性的:同一文件夹生成完全相同的
字节。
pdfl pack profiles/print-shop --name print-profile --version 1.0.0
pdfl add
安装本地软件包,并校验清单中的哈希。
pdfl add print-profile.pdflpkg
# 安装到 ./pdfl_profiles/print-profile@1.0.0/
pdfl run pdfl_profiles/print-profile@1.0.0/prepress.pdfl file.pdf
若任一文件的哈希与记录不符,安装会被拒绝 — 损坏或被篡改的包不会进入。
远程仓库和数字签名不在本版本范围内:
add从本地文件安装。
pdfl fingerprint
本机指纹 —— 发给供应方以换取许可证的值。
pdfl fingerprint generate
指纹单独输出到标准输出,说明文字走标准错误,因此
pdfl fingerprint generate 2>/dev/null 得到的就是可直接管道传递的值。
$ pdfl fingerprint generate
Device fingerprint for this machine:
1a7553e711c53306be083ea8927c9cbe
Send it to your vendor to be issued a license.
It changes if the operating system is reinstalled.
指纹来自系统的机器标识符(
/etc/machine-id、IOPlatformUUID或MachineGuid)。重装操作系统后它会变,由同一镜像克隆的虚拟机共享同一个值。 对于每次运行都销毁机器的 CI 和容器,则有不看设备的seatless许可证。
pdfl license
校验收到的许可证。pdfl 只做校验:签发由供应方完成,所用的私钥不随二进制
文件分发。
pdfl license check <token>
$ pdfl license check "$(cat license.txt)"
signature: ok
customer: Example Print Shop
expires: 2027-01-01
features: all
device: 1a7553e711c53306be083ea8927c9cbe
this machine: matches
许可证对本机有效时退出码为 0,否则为 2 —— 包括签名正确但许可证属于另一台
机器的情况,这时消息会明确说明。
| 选项 | 功能 |
|---|---|
--pubkey <base64> |
使用指定公钥,而非编译时嵌入的那个 |
哪些命令需要许可证
run、fix、watch、compare 和 inspect 在本机没有有效许可证时以退出码 2
停止。
fingerprint generate 绝不需要——正是它产出申请许可证所需的值。lint、
fmt、doc 和 pack 只处理脚本、不碰 PDF,同样不需要。
令牌按以下顺序查找:
$PDFL_LICENSE—— 面向 CI 的方式,在那里它作为 secret~/.config/pdfl/license- 可执行文件旁的
pdfl.license
$ pdfl run profile.pdfl file.pdf
error: no license found
Run 'pdfl fingerprint generate' and send the value to your vendor
to be issued a license. Then set PDFL_LICENSE, or save the token to
/home/you/.config/pdfl/license.
seatless许可证有执行次数上限,记在~/.config/pdfl/state。同一个文件还记录 上次执行的时间,若时钟被回拨则拒绝运行——留有一小时容差,以免与时间同步冲突。
← 标准库 · 目录 · 下一章:实用范例 →