Usando a substituição de processos (ou similar) para exibir páginas man como pdf sem tempfiles

0

Eu tenho uma função Bash para exibir man pages renderizadas como postscript, em um PDF:

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

( Atualização : eu removi complicações periféricas como gerar dinamicamente o nome do arquivo temporário e usar 'nohup')

Isso funciona bem. Para uma captura de tela em uso, consulte o link .

Para minha própria edificação, tentei implementá-lo sem usar tempfiles. Por exemplo, usando a substituição de processos:

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

Isso não funciona. Evince exibe um erro em sua GUI:

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

Por quê? Como posso gerar e visualizar o PDF sem gerar arquivos intermediários?

A mensagem de erro acima é diferente das mensagens que o evidince mostra para arquivos ausentes ou vazios, então não é simplesmente isso.

Atualização: Para obter mais informações, tentei substituir 'evince' por 'ls':

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

onde dircolors está colorido:

  • /dev/fd/63 como 'ORPHAN' (um link simbólico que aponta para um arquivo inexistente) e
  • pipe:[196475] como 'MISSING' (um arquivo inexistente apontado por um link simbólico)

Então, talvez o evince esteja recebendo um link apontando para um arquivo que não existe? Para imitar isso, criei um link simbólico que aponta para um arquivo inexistente e, em seguida, o abri com 'evince'. Mas em vez da mensagem "PDF está danificado" acima, isso me dá "Nenhum arquivo ou diretório".

Update: Acho que os tipos de arquivos ORPHAN / MISSING são um arenque vermelho. Eu vejo o mesmo symlink ORPHAN / MISSING ao fazer uma substituição de processo muito simples:

$ ls -l <( echo 123 )

e usando o mesmo pipeline man|ps2pdt funciona bem quando a substituição do processo é alimentada para diff :

$ diff <(man -t ls | ps2pdf - - | tr "
function psman () {
    man -t "$@" | ps2pdf - /tmp/manpage.pdf
    evince /tmp/manpage.pdf
}
" "0") <(man -t ls | ps2pdf - - | tr "
$ evince <(man -t ls | ps2pdf - -)
" "0") 248c248 < /ID [<95A81B38FAE8E6FE3C899586A1DEE861><95A81B38FAE8E6FE3C899586A1DEE861>] --- > /ID [<2F9164BD9265C8540A4A8E7068076344><2F9164BD9265C8540A4A8E7068076344>]

(Aqui adicionei 'tr' aos pipelines para eliminar caracteres nulos / zero na saída do pdf, de modo que o diff trataria os arquivos como textuais em vez de binários.)

Então, em resumo, não tenho idéia do motivo pelo qual recebo o erro "PDF está danificado" acima. Meu objetivo, além de entender, é visualizar o PDF gerado sem gerar nenhum arquivo pelo caminho.

    
por Jonathan Hartley 22.08.2017 / 21:54

3 respostas

1

Apenas um palpite, mas plausível:

evince procura através do "arquivo", o fluxo que recebe não é procurado. Compare Por que a substituição do processo BASH não funciona com alguns comandos?

Isso significa que (quase?) é impossível alcançar o que você deseja sem nenhum arquivo intermediário. O melhor que posso pensar é um script 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 &

Comentários, armadilhas, etc.:

  1. Quando $tmpd é /dev/shm , um arquivo temporário é criado na memória . Eu acho que é tão perto de "sem gerar arquivos intermediários" como você pode facilmente obter, mantendo-o procurável.
  2. Independentemente de onde esteja, devemos removê-lo depois. Se o script for interrompido (por exemplo, com Ctrl + C ) entre mktemp e rm , o arquivo sobreviverá e não o queremos. Existem poucas abordagens para este problema, você pode trap sinais se quiser; Escolhi executar toda a sequência em segundo plano ( ( … ) & ), o que pode ser bom o suficiente.
  3. Meu evince não abre um arquivo de /dev/shm , a menos que seu nome termine com .pdf (esse comportamento não diferencia maiúsculas de minúsculas). É por isso que há .pdf no modelo de nome de arquivo. Não há esse problema em /tmp . Por quê? Não sei.
  4. O modelo de nome de arquivo é criado com $* para torná-lo um pouco significativo (exibido no título da janela evince ).
por 23.08.2017 / 16:53
1

Arquivos PDF são uma coleção de objetos inter-relacionados, identificados com ids. No final do arquivo, há um índice para os objetos, que mapeia os ids para arquivar deslocamentos. É realmente impossível usar um arquivo PDF sem este índice, então a abordagem usual para ler um arquivo PDF é procurar fechar até o final e tentar encontrar o início do índice, que é então lido na memória. O índice indica qual objeto é o objeto raiz e, a partir daí, você pode percorrer o gráfico do objeto, sempre usando o índice para localizar o deslocamento do arquivo de cada objeto relacionado.

Em teoria, você pode ler (ou mapear) todo o arquivo na memória, mas isso não funcionaria com arquivos realmente grandes e o PDF é destinado a lidar com arquivos realmente grandes (e, de fato, arquivos PDF com qualidade de impressão pode ser muito grande). Então, buscar é uma parte intrínseca do uso de um arquivo PDF, e a substituição de processos não suporta a busca.

Existem outras aplicações de linha de comando que precisam procurar, ou pensam que sim. (Às vezes, a busca é apenas uma tentativa do programador de descobrir o tamanho do arquivo, por conveniência.) Há outros formatos de arquivo que colocam um índice no final (como a compactação Zip) e realmente dependem da pesquisa. Bancos de dados, por exemplo, nem mesmo têm um senso de leitura linear, e provavelmente ninguém pensaria em fornecer um arquivo de apoio de banco de dados por meio de substituição de processo. Mas o PDF é um tipo de criança-propaganda para processamento não-linear, e isso às vezes é surpreendente.

    
por 12.06.2018 / 06:51
-1

Você só precisa adicionar o nome do arquivo, por exemplo, use:

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

Isso criará o arquivo man_ls.pdf em seu diretório pessoal

    
por 22.08.2017 / 21:59

Tags