11. Comandos del CLI
← Biblioteca estándar · Índice · Siguiente: Recetas →
Doce comandos: cuatro que trabajan con PDF, cuatro sobre los scripts, dos de distribución y dos de licencias.
| Comando | Qué hace |
|---|---|
run |
Valida un PDF con un script |
compare |
Compara dos versiones de un PDF |
watch |
Vigila una carpeta y valida lo que llega |
fix |
Aplica correcciones y guarda un PDF nuevo |
inspect |
Resumen rápido de un PDF |
lint |
Analiza un script sin ejecutarlo |
fmt |
Formatea un script |
doc |
Genera la documentación de un script |
pack |
Empaqueta perfiles y bases |
add |
Instala un paquete |
fingerprint |
Huella del equipo |
license |
Verificación de licencia |
Códigos de salida
Todos los comandos que validan usan la misma convención:
| Código | Significado |
|---|---|
0 |
Todo pasó |
1 |
Solo advertencias |
2 |
Errores de validación, o PDF ilegible |
3 |
Error de sintaxis en el script |
En scripts de shell:
pdfl run perfil.pdfl archivo.pdf > informe.json
case $? in
0) echo "aprobado" ;;
1) echo "aprobado con salvedades" ;;
2) echo "rechazado — mira informe.json" ;;
3) echo "error en el script de validación" ;;
esac
pdfl run
Valida un PDF con un script.
pdfl run <script.pdfl> <entrada.pdf> [opciones]
| Opción | Por defecto | Qué hace |
|---|---|---|
--output json|csv|html|pdf |
json |
Formato del informe |
--output-file <archivo> |
— | Escribe en un archivo en lugar del stdout |
--fail-on error|warning |
error |
Con warning, las advertencias también dan exit 2 |
--verbose |
— | Información adicional por stderr |
# Informe JSON en la terminal
pdfl run prepress.pdfl revista.pdf
# HTML para enviar al cliente
pdfl run prepress.pdfl revista.pdf --output html --output-file informe.html
# PDF de auditoría (el formato pdf siempre escribe en archivo)
pdfl run prepress.pdfl revista.pdf --output pdf --output-file informe.pdf
# CSV para hoja de cálculo
pdfl run prepress.pdfl revista.pdf --output csv --output-file hallazgos.csv
# Estricto: las advertencias también suspenden
pdfl run prepress.pdfl revista.pdf --fail-on warning
El informe JSON
{
"script_name": "prepress.pdfl",
"input_file": "revista.pdf",
"profile": "offset-revista",
"status": "FAIL",
"total_pages_analyzed": 120,
"error_count": 2,
"warning_count": 0,
"info_count": 0,
"diagnostics": [
{
"id": "PDFL-001",
"severity": "error",
"check_name": "Cobertura de tinta",
"message": "page 7: 324% ink (limit 300%)",
"line": 12
}
]
}
El mismo PDF con el mismo script genera siempre el mismo informe, byte a byte: se puede versionar y comparar en CI.
pdfl compare
Compara dos versiones de un PDF: texto, estructura y metadatos.
pdfl compare <v1.pdf> <v2.pdf> [opciones]
| Opción | Por defecto | Qué hace |
|---|---|---|
--output json|csv|html|pdf |
json |
Formato |
--output-file <archivo> |
— | Escribe en un archivo |
--normalize |
— | Ignora mayúsculas y espaciado |
--ignore-dates |
— | Enmascara las fechas antes de comparar |
--similarity-threshold <0-100> |
100 |
Similitud mínima aceptable |
# Comparación simple
pdfl compare aprobado_v1.pdf nuevo_v2.pdf
# Tolerando pequeñas diferencias de formato y de fechas
pdfl compare aprobado_v1.pdf nuevo_v2.pdf --normalize --ignore-dates
# Acepta hasta un 1% de diferencia; por debajo de eso es un error
pdfl compare v1.pdf v2.pdf --similarity-threshold 99 \
--output html --output-file diff.html
Cómo funciona
- Las páginas se alinean por contenido, no por número: si se insertó una página en medio, el comparador lo detecta en vez de marcar como distinto todo lo que viene después. Funciona en documentos de más de mil páginas.
- Cada página alineada recibe una nota de similitud y una muestra de las líneas
que cambiaron (
-salió,+entró). - Los metadatos distintos generan advertencia; el texto alterado genera error si queda por debajo del umbral, y advertencia si queda por encima.
- El informe trae el campo
similaritycon la nota general.
page 4 → 4: similarity 97.8% | -título original cuentos | +título revisado
pdfl watch
Vigila una carpeta y valida cada PDF que llega o que cambia.
pdfl watch <carpeta> --script <script.pdfl> [opciones]
| Opción | Por defecto | Qué hace |
|---|---|---|
--pattern <glob> |
*.pdf |
Qué archivos procesar |
--exclude <glob> |
— | Cuáles ignorar |
--output-dir <carpeta> |
junto al PDF | Dónde escribir los informes |
--depth <n> |
1 |
Niveles de subcarpeta |
--debounce <ms> |
1000 |
Espera a que el archivo deje de copiarse |
--report json|csv|html|pdf |
json |
Formato de los informes |
--fail-fast |
— | Se detiene en el primer error |
--once |
— | Procesa lo que ya hay y sale |
# Carpeta de entrada de la imprenta, funcionando de continuo
pdfl watch entrada/ --script preflight.pdfl --output-dir informes/ --report html
# Modo lote para CI: procesa todo y sale con el peor código
pdfl watch entrada/ --script preflight.pdfl --once
echo "resultado: $?"
# Ignorando borradores
pdfl watch entrada/ --script preflight.pdfl \
--pattern "*.pdf" --exclude "*_borrador*"
El debounce existe porque los archivos grandes llegan poco a poco: el watch solo procesa cuando el archivo deja de cambiar, y así evita leer un PDF a medias.
Los informes salen como <nombre>.report.json (o .csv, .html, .pdf).
pdfl fix
Aplica las operaciones fix:: y guarda un PDF nuevo. Los detalles están en el
capítulo 8.
pdfl fix <entrada.pdf> <script.pdfl> --output <salida.pdf> [opciones]
| Opción | Qué hace |
|---|---|
--output <archivo> |
PDF de salida (obligatorio) |
--dry-run |
Lista las operaciones sin guardar |
--report json|csv|html|pdf |
Formato del informe |
--report-file <archivo> |
Escribe el informe en un archivo |
# Ver qué se haría, sin tocar nada
pdfl fix original.pdf normalizar.pdfl --output salida.pdf --dry-run
# Aplicarlo de verdad
pdfl fix original.pdf normalizar.pdfl --output corregido.pdf
pdfl inspect
Resumen rápido de un PDF, sin script.
pdfl inspect <archivo.pdf>
File: revista.pdf
Size: 26 KB (27284713 bytes)
SHA-256: af1029842e5bfeae338ead82fb449ef851be742b1d63117c12596e3ea123a616
Pages: 120
Page size: 496 x 709 pt
Boxes: MediaBox, TrimBox, BleedBox
Metadata:
Title: Revista Ejemplo
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
Es el primer comando que conviene ejecutar cuando llega un archivo nuevo: en segundos sabes si merece la pena abrirlo.
pdfl lint
Analiza un script sin ejecutarlo y señala problemas de calidad.
pdfl lint <script.pdfl>
Detecta:
- variables, parámetros de bloque y funciones declarados y nunca usados
(ponles el prefijo
_para silenciarlos:_page) - checks duplicados o vacíos
- espacio de nombres desconocido (
text::,struct::,visual::,prepress::,codes::,fix::,data::) assert/requirefuera de cualquier check- uso de
fix::(que solo se ejecuta enpdfl fix)
$ pdfl lint perfil.pdfl
perfil.pdfl: warning: variable 'LIMITE' declared and never used
perfil.pdfl: warning: check "Fuentes" declared 2 times
Sale con el código 1 si hay advertencias, así que sirve en CI.
pdfl fmt
Formatea el script: sangría de 2 espacios, espaciado coherente y líneas en
blanco colapsadas. Conserva los comentarios y las unidades (3mm sigue siendo
3mm).
pdfl fmt <script.pdfl> # formatea en el sitio
pdfl fmt <script.pdfl> --check # no modifica; sale con 1 si no cumple el formato
# En CI, para garantizar el formato en todo el equipo
for f in perfiles/*.pdfl; do pdfl fmt "$f" --check || exit 1; done
pdfl doc
Genera la documentación de un script a partir del propio código.
pdfl doc <script.pdfl> [--output markdown|html]
Produce: el perfil, una tabla de constantes, las funciones, los imports y —para
cada check— sus etiquetas y qué valida (los mensajes de los assert se
convierten en la descripción).
# Markdown para el repositorio
pdfl doc prepress.pdfl > docs/perfil-prepress.md
# HTML para enviárselo a quien no lee código
pdfl doc prepress.pdfl --output html > perfil.html
Es el artefacto para que el jefe de producción entienda qué valida el perfil sin abrir el script.
pdfl pack
Empaqueta scripts y bases en un archivo .pdflpkg distribuible.
pdfl pack <carpeta> [--name <nombre>] [--version <versión>] [--output <archivo>]
Incluye los .pdfl, .csv, .txt, .json y .xlsx de la carpeta (de forma
recursiva), con un manifest.json que registra el SHA-256 de cada archivo. El
paquete es determinista: la misma carpeta genera bytes idénticos.
pdfl pack perfiles/imprenta --name perfil-imprenta --version 1.0.0
# crea perfil-imprenta.pdflpkg
pdfl add
Instala un paquete local comprobando los hashes del manifiesto.
pdfl add <paquete.pdflpkg> [--dir <carpeta>]
pdfl add perfil-imprenta.pdflpkg
# instala en ./pdfl_profiles/perfil-imprenta@1.0.0/
pdfl run pdfl_profiles/perfil-imprenta@1.0.0/prepress.pdfl archivo.pdf
Si algún archivo tiene un hash distinto del registrado, la instalación se rechaza: un paquete corrupto o manipulado no entra.
El repositorio remoto y la firma digital no forman parte de esta versión: el
addinstala desde archivos locales.
pdfl fingerprint
La huella de este equipo: el valor que el cliente envía para recibir una licencia.
pdfl fingerprint generate
Sale sola por el stdout; el texto de apoyo va por stderr, así que
pdfl fingerprint generate 2>/dev/null da un valor listo para canalizar.
$ 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.
La huella sale del identificador de máquina del sistema (
/etc/machine-id,IOPlatformUUIDoMachineGuid). No sobrevive a una reinstalación del sistema, y las máquinas virtuales clonadas de la misma imagen comparten el valor. Para CI y contenedores —donde la máquina se destruye en cada ejecución— existe la licenciaseatless, que no mira el equipo.
pdfl license
Comprueba una licencia recibida. pdfl solo verifica: quien las emite es el
proveedor, con la clave privada, que no acompaña al binario.
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
Sale con 0 si la licencia vale para esta máquina y con 2 si no, incluso
cuando la firma es correcta pero la licencia es de otro equipo, caso en el que
el mensaje lo dice exactamente.
| Opción | Qué hace |
|---|---|
--pubkey <base64> |
Clave pública a usar, en lugar de la compilada en el binario |
Dónde se exige la licencia
run, fix, watch, compare e inspect se detienen con el código 2 si no
hay una licencia válida para este equipo. fingerprint generate nunca la
exige: es el que produce el valor necesario para pedir una licencia. lint,
fmt, doc y pack solo tocan scripts, nunca un PDF, y tampoco la exigen.
El token se busca en este orden:
$PDFL_LICENSE— el camino para CI, donde se convierte en un secreto~/.config/pdfl/licensepdfl.licensejunto al ejecutable
$ pdfl run perfil.pdfl archivo.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/tu_usuario/.config/pdfl/license.
Una licencia
seatlesstiene un tope de ejecuciones, contado en~/.config/pdfl/state. El mismo archivo guarda cuándo fue la última ejecución y se niega a ejecutarse si el reloj va hacia atrás, con una hora de tolerancia, para no pelearse con la sincronización horaria.