Uso de la sustitución de procesos (o similar) para mostrar páginas de manual como pdf sin archivos temporales

0

Tengo una función Bash para mostrar las páginas de manual representadas como postscript, en un PDF:

function psman () {
    man -t "$@" | ps2pdf - /tmp/manpage.pdf
    evince /tmp/manpage.pdf
}

( Actualizar : Eliminé las complicaciones periféricas como generar dinámicamente el nombre del archivo temporal y usar 'nohup')

Esto funciona bien. Para una captura de pantalla en uso, vea https://www.tartley.com/postscript-formatted-man-pages .

Para mi propia edificación, traté de implementarla sin usar archivos temporales. Por ejemplo, utilizando la sustitución de procesos:

$ evince <(man -t ls | ps2pdf - -)

Esto no funciona. Evince muestra un error en su GUI:

Unable to open document "file:///dev/fd/63".
PDF document is damaged

¿Por qué? ¿Cómo puedo generar y ver el PDF sin generar ningún archivo intermedio?

El mensaje de error anterior es diferente de lo que muestran los mensajes de los archivos faltantes o vacíos, así que no es simplemente eso.

Actualizar: Para obtener más información, intenté reemplazar 'evince' con 'ls':

$ ls -l <(man -t ls | ps2pdf - -)
lr-x------. 1 jhartley jhartley 64 Aug 23 08:59 /dev/fd/63 -> pipe:[196475]

donde dircolors es colorante:

  • /dev/fd/63 como 'ORPHAN' (un enlace simbólico que apunta a un archivo inexistente), y
  • pipe:[196475] como 'MISSING' (un archivo inexistente apuntado por un enlace simbólico)

Entonces, ¿quizás a Evince se le está dando un enlace que apunta a un archivo que no existe? Para imitar esto, creé un enlace simbólico que apunta a un archivo inexistente, luego lo abrí con 'evince'. Pero en lugar del mensaje "El PDF está dañado" más arriba, esto me da "No existe tal archivo o directorio".

Actualizar: Creo que los tipos de archivo ORPHAN / MISSING son una pista falsa. Veo el mismo enlace simbólico ORPHAN / MISSING cuando hago una sustitución de proceso muy simple:

$ ls -l <( echo 123 )

y usando el mismo man|ps2pdt La tubería funciona bien cuando la sustitución del proceso se alimenta a diff:

$ diff <(man -t ls | ps2pdf - - | tr "\0" "0") <(man -t ls | ps2pdf - - | tr "\0" "0")
248c248
< /ID [<95A81B38FAE8E6FE3C899586A1DEE861><95A81B38FAE8E6FE3C899586A1DEE861>]
---
> /ID [<2F9164BD9265C8540A4A8E7068076344><2F9164BD9265C8540A4A8E7068076344>]

(Aquí agregué 'tr' a las tuberías para eliminar los caracteres nulos / cero en la salida pdf, de modo que diff trataría los archivos como textuales en lugar de binarios).

Entonces, en resumen, no tengo idea de por qué recibo el error "El PDF está dañado" más arriba. Mi objetivo, aparte de comprender, es ver el PDF generado sin generar ningún archivo en el camino.

Jonathan Hartley
fuente
Estoy empezando a pensar que mi problema está relacionado con la forma en que se manifiesta la evidencia y se abre desde los archivos. Otras herramientas (como 'diff' como se describe anteriormente) parecen abrir el nombre de archivo resultante de la sustitución de mi proceso sin problemas.
Jonathan Hartley
Me doy cuenta de que evince <( cat man-ls.pdf ) se abre sin errores, mostrando 4 páginas (el número correcto), pero todas las páginas están en blanco. Como si en parte hubiera leído el archivo con éxito, pero luego falló en algún punto.
Jonathan Hartley
Creo que tal vez debería haber planteado esto en unix.stackexchange.com
Jonathan Hartley

Respuestas:

1

Solo una conjetura, pero plausible:

evince busca a través del "archivo", la secuencia que recibe no se puede buscar. Comparar ¿Por qué la sustitución del proceso BASH no funciona con algunos comandos?

Esto significa que es (¿casi?) Imposible lograr lo que desea sin ningún archivo intermedio. Lo mejor que se me ocurre es un guión como este:

#!/bin/bash

tmpd="/dev/shm"

( tmpf="$(mktemp -p "$tmpd" "tmp [man $*] XXX.pdf")"
man -t "$@" | ps2pdf - > "$tmpf"
evince "$tmpf"
rm "$tmpf" ) 2>/dev/null &

Observaciones, trampas, etc .:

  1. Cuando $tmpd es /dev/shm, se crea un archivo temporal en memoria . Supongo que es lo más cercano a "sin generar ningún archivo intermedio" que pueda obtener fácilmente, al tiempo que lo puede buscar.
  2. Independientemente de dónde se encuentre, debemos eliminarlo después. Si el script se interrumpe (por ejemplo, con Ctrl + do ) Entre mktemp y rm, el archivo sobrevive y no lo queremos. Hay pocos enfoques para este problema, puede trap Señales si quieres; Elegí ejecutar toda la secuencia en segundo plano ( ( … ) & ) que puede ser lo suficientemente bueno.
  3. Mi evince no abrirá un archivo de /dev/shm a menos que su nombre termine con .pdf (Este comportamiento es insensible a mayúsculas y minúsculas). Por eso hay .pdf en la plantilla de nombre de archivo. No hay tal problema en /tmp. ¿Por qué? No lo sé.
  4. La plantilla de nombre de archivo se crea con $* en ella para hacerla algo significativa (se muestra en el título de evince ventana).
Kamil Maciorowski
fuente
Esto tiene mucho sentido. Gracias por el enlace. Aprendí algo hoy.
Jonathan Hartley
1

Los archivos PDF son una colección de objetos interrelacionados, identificados con identificadores. Al final del archivo, hay un índice para los objetos, que asigna las identificaciones a las compensaciones de archivos. Es realmente imposible utilizar un archivo PDF sin este índice, por lo que el enfoque habitual para leer un archivo PDF es intentar cerrar el final e intentar encontrar el principio del índice, que luego se lee en la memoria. El índice indica qué objeto es el objeto raíz, y desde allí puede recorrer el gráfico del objeto, utilizando siempre el índice para encontrar el desplazamiento del archivo de cada objeto relacionado.

En teoría, podría leer (o mmap) todo el archivo en la memoria, pero eso no funcionaría con archivos realmente grandes y el PDF está destinado a poder hacer frente a archivos realmente grandes (y, de hecho, los archivos PDF con calidad de impresión pueden ser realmente grande). Por lo tanto, la búsqueda es una parte intrínseca del uso de un archivo PDF, y la sustitución de procesos no es compatible con la búsqueda.

Hay otras aplicaciones de línea de comando que necesitan buscar, o pensar que lo hacen. (A veces, la búsqueda es solo un intento del programador para averiguar qué tan grande es el archivo, por conveniencia). Hay otros formatos de archivo que ponen un índice al final (como la compresión Zip), y realmente se basan en la búsqueda. Las bases de datos, por ejemplo, ni siquiera tienen un sentido de lectura lineal, y probablemente nadie pensaría en proporcionar un archivo de respaldo de base de datos a través de la sustitución de procesos. Pero el PDF es un tipo de elemento secundario para el procesamiento no lineal, y eso a veces es sorprendente.

rici
fuente
-1

Solo necesita agregar el nombre del archivo, por ejemplo, use:

(man -t ls | ps2pdf - ~/man_ls.pdf) > evince

Esto va a crear el man_ls.pdf archivo en su directorio personal

Genaro Morales
fuente
Gracias por las ideas, pero no entiendo todavía. ¿Estás seguro de que quisiste decir '& gt;' cerca del final de esa fiesta? Escribe un archivo vacío llamado 'evidencia'
Jonathan Hartley
Recuerde, mi objetivo es ejecutar el programa llamado 'evince' (un visor de PDF gnome) en el PDF, sin escribir ningún archivo en el camino.
Jonathan Hartley
Mis disculpas. Voy a marcar esta respuesta hacia abajo porque el comando no funciona, y la explicación no parece abordar mi pregunta en absoluto. Disculpas si estoy malinterpretando.
Jonathan Hartley
¿Por qué intentas escribir un archivo pdf sin usar ningún archivo? debe almacenar en algún lugar la información, si no está intentando obtener archivos temporales o cualquier otro archivo, ¿cuál es su enfoque?
Genaro Morales
Hola genaro El enfoque de Bash para hacer esto es una característica llamada proceso de sustitución, que utiliza el cmd1 <( cmd2 ) sintaxis. El stdout de cmd2 (en mi ejemplo, ps2pdf) va a una tubería, y esa tubería recibe un nombre en el sistema de archivos, y ese nombre se pasa a cmd1 (en mi ejemplo, evince). cmd1 puede abrir el nombre de archivo que se le dio, leerlo y obtener la salida estándar de cmd2. Ninguno de los dos comandos tiene idea de que se está utilizando la sustitución de procesos. Sin embargo, en ningún momento Bash escribe bytes en el disco. Esto es todo en memoria, al igual que la redirección y amp; tubería. El punto es para el rendimiento, & amp; educacion personal
Jonathan Hartley