Menggunakan subtitusi proses (atau yang serupa) untuk menampilkan halaman manual sebagai pdf tanpa tempfile

1

Saya memiliki fungsi Bash untuk menampilkan halaman manual yang dibuat sebagai catatan tambahan, dalam PDF:

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

( Pembaruan : Saya menghapus komplikasi periferal seperti secara dinamis menghasilkan nama file temp, dan menggunakan 'nohup')

Ini berfungsi dengan baik. Untuk tangkapan layar yang digunakan, lihat https://www.tartley.com/postscript-formatted-man-pages .

Untuk perbaikan saya sendiri, saya mencoba mengimplementasikannya tanpa menggunakan tempfile. Misalnya, menggunakan subtitusi proses:

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

Ini tidak bekerja Evince menampilkan kesalahan dalam GUI-nya:

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

Mengapa? Bagaimana saya bisa menghasilkan dan melihat PDF tanpa menghasilkan file perantara?

Pesan kesalahan di atas berbeda dari pesan yang ditampilkan untuk file yang hilang atau kosong, jadi bukan hanya itu.

Pembaruan: Untuk mendapatkan info lebih lanjut, saya mencoba mengganti 'evince' dengan 'ls':

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

tempat dircolors mewarnai:

  • /dev/fd/63 sebagai 'ORPHAN' (tautan simbolis yang menunjuk ke file yang tidak ada), dan
  • pipe:[196475] sebagai 'MISSING' (file tidak ada yang diarahkan oleh tautan simbolik)

Jadi mungkin evince hanya diberi tautan yang menunjuk ke file yang tidak ada? Untuk meniru ini, saya membuat tautan simbolis yang menunjuk ke file yang tidak ada, lalu membukanya dengan 'evince'. Tetapi alih-alih pesan 'PDF rusak' di atas, ini memberi saya "Tidak ada file atau direktori."

Pembaruan: Saya pikir tipe file ORPHAN / MISSING adalah herring merah. Saya melihat symlink Orphan / MISSING yang sama ketika melakukan substitusi proses yang sangat sederhana:

$ ls -l <( echo 123 )

dan menggunakan man|ps2pdtpipa yang sama berfungsi dengan baik ketika proses substitusi diumpankan ke diff:

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

(Di sini saya menambahkan 'tr' ke jalur pipa untuk menghilangkan karakter nol / nol dalam output pdf, sehingga diff akan memperlakukan file sebagai tekstual alih-alih biner.)

Jadi, secara ringkas, saya tidak tahu mengapa saya mendapatkan kesalahan "PDF rusak" di atas. Tujuan saya, selain memahami, adalah untuk melihat PDF yang dihasilkan tanpa menghasilkan file apa pun di sepanjang jalan.

Jonathan Hartley
sumber
Saya mulai berpikir masalah saya terkait dengan cara evince sendiri terbuka dan membaca dari file. Alat-alat lain (seperti 'diff' seperti yang dijelaskan di atas) tampaknya membuka nama file yang dihasilkan dari substitusi proses saya tanpa masalah.
Jonathan Hartley
Saya perhatikan bahwa evince <( cat man-ls.pdf )terbuka tanpa kesalahan, menampilkan 4 halaman (nomor yang benar), tetapi semua halaman kosong. Seperti sebagian berhasil membaca file, tetapi kemudian gagal di beberapa titik.
Jonathan Hartley
Saya pikir mungkin saya harus berpose di unix.stackexchange.com
Jonathan Hartley

Jawaban:

2

Hanya tebakan, tapi masuk akal:

evincemencari melalui "file", aliran yang didapatnya tidak dapat dicari. Bandingkan Mengapa substitusi proses BASH tidak berfungsi dengan beberapa perintah?

Ini berarti (hampir?) Mustahil untuk mencapai apa yang Anda inginkan tanpa file perantara. Yang terbaik yang bisa saya pikirkan adalah skrip seperti ini:

#!/bin/bash

tmpd="/dev/shm"

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

Komentar, jebakan dll .:

  1. Ketika $tmpdadalah /dev/shm, file sementara yang dibuat dalam memori . Saya kira itu dekat dengan "tanpa menghasilkan file perantara" seperti yang Anda dapat dengan mudah, sambil tetap dicari.
  2. Terlepas dari di mana tempatnya, kita harus menghapusnya setelah itu. Jika skrip terputus (misalnya dengan Ctrl+ C) antara mktempdan rm, file tersebut bertahan dan kami tidak menginginkannya. Ada beberapa pendekatan untuk masalah ini, Anda dapat trapmemberi sinyal jika Anda mau; Saya memilih untuk menjalankan seluruh urutan di latar belakang ( ( … ) &) yang mungkin cukup bagus.
  3. Saya evincetidak akan membuka file dari /dev/shmkecuali namanya diakhiri dengan .pdf(perilaku ini tidak peka huruf besar-kecil). Itu sebabnya ada .pdfdi template nama file. Tidak ada masalah seperti itu di /tmp. Mengapa? Saya tidak tahu
  4. Templat nama file dibuat dengan $*di dalamnya untuk membuatnya agak bermakna (ditampilkan dalam judul evincejendela).
Kamil Maciorowski
sumber
Ini sangat masuk akal. Terima kasih untuk tautannya. Saya belajar sesuatu hari ini.
Jonathan Hartley
1

File PDF adalah kumpulan objek yang saling terkait, diidentifikasi dengan id. Di akhir file, ada indeks ke objek, yang memetakan id ke file offset. Sangat tidak mungkin menggunakan file PDF tanpa indeks ini, jadi pendekatan yang biasa digunakan untuk membaca file PDF adalah berusaha mendekati akhir dan mencoba menemukan awal indeks, yang kemudian dibaca ke dalam memori. Indeks menunjukkan objek mana yang merupakan objek root, dan dari sana Anda dapat berjalan melalui grafik objek, selalu menggunakan indeks untuk menemukan offset file dari setiap objek terkait.

Secara teori Anda bisa membaca (atau mmap) seluruh file ke dalam memori, tetapi itu tidak akan berfungsi dengan file yang sangat besar dan PDF dimaksudkan untuk dapat mengatasi file yang sangat besar (dan, memang, kualitas cetak file PDF dapat benar-benar besar). Jadi mencari adalah bagian intrinsik dari penggunaan file PDF, dan proses substitusi tidak mendukung pencarian.

Ada aplikasi baris perintah lain yang perlu dicari, atau berpikir mereka melakukannya. (Kadang-kadang pencarian hanya merupakan upaya oleh programmer untuk mencari tahu seberapa besar file tersebut, untuk kenyamanan.) Ada format file lain yang menempatkan indeks pada akhirnya (seperti kompresi Zip), dan benar-benar mengandalkan pencarian. Basis data, misalnya, bahkan tidak benar-benar memiliki perasaan membaca linear, dan mungkin tidak ada yang akan berpikir untuk menyediakan file dukungan database melalui proses substitusi. Tapi PDF adalah semacam poster anak untuk pemrosesan non-linear, dan itu kadang mengejutkan.

rici
sumber
-1

Anda hanya perlu menambahkan nama file misalnya gunakan:

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

Ini akan membuat man_ls.pdffile di direktori home Anda

Genaro Morales
sumber
Terima kasih atas ide-idenya, tapi saya belum mengerti. Apakah Anda yakin maksud Anda mendekati akhir bash itu? Itu menulis file kosong yang disebut 'evince'
Jonathan Hartley
Ingat, tujuan saya adalah menjalankan program yang disebut 'evince' (penampil PDF gnome) di PDF, tanpa menulis file apa pun di sepanjang jalan.
Jonathan Hartley
Permintaan maaf saya. Saya akan menandai jawaban ini karena perintahnya tidak berfungsi, dan penjelasannya sepertinya tidak menjawab pertanyaan saya sama sekali. Maaf jika saya salah menafsirkan.
Jonathan Hartley
Mengapa Anda mencoba menulis file pdf tanpa menggunakan file apa pun? Anda harus menyimpan informasi di suatu tempat, jika Anda tidak mencoba untuk mendapatkan file temp atau file apa pun pendekatan Anda?
Genaro Morales
Hai Genaro. Pendekatan Bash untuk melakukan ini adalah fitur yang disebut substitusi proses, menggunakan cmd1 <( cmd2 )sintaksis. Stdout dari cmd2(dalam contoh saya, ps2pdf) masuk ke sebuah pipa, dan pipa itu diberi nama pada sistem file, dan nama itu diteruskan ke cmd1 (dalam contoh saya, evince). cmd1 dapat membuka nama file yang diberikan, membacanya, dan mendapatkan stdout dari cmd2. Tidak ada perintah yang tahu bahwa proses substitusi sedang digunakan. Namun, tidak ada titik Bash menulis byte ke disk. Ini semua ada di memori, seperti pengalihan & pipa. Intinya adalah untuk kinerja, & pendidikan pribadi.
Jonathan Hartley