Piping multiplas entradas para o Ghostscript

1

Estou tentando criar um comando Linux de uma linha para combinar dois arquivos PDF - que são baixados de uma URL - usando o Ghostscript. No entanto, eu não quero criar nenhum arquivo temporário (tudo deve ser feito na memória).

O comando a seguir parece não funcionar (tentei conseguir isso por meio de substituição de processo).

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=combined.pdf <(curl http://example.com/one.pdf) <(curl http://example.com/two.pdf)

Quando eu executo este comando, ele me dá o erro abaixo.

**** Warning:  An error occurred while reading an XREF table.
**** The file has been damaged.  This may have been caused
**** by a problem while converting or transfering the file.
**** Ghostscript will attempt to recover the data.
Error: /ioerror in --run--
Current allocation mode is local
Last OS error: Illegal seek
GPL Ghostscript 9.18: Unrecoverable error, exit code 1

Acredito que o que está acontecendo é que o comando Ghostscript está sendo executado antes que os dois PDFs de entrada tenham a chance de concluir o download, talvez haja uma maneira de esperar que isso aconteça.

    
por Zak 17.10.2016 / 19:16

1 resposta

3

Esta não é a resposta que você está procurando, mas é uma alternativa prática.

Primeiro, alguns antecedentes:

Todos os tipos de canal têm a desvantagem que o leitor não pode buscar neles, incluindo os que o Bash usa para <(command-list) . Não sei se o GhostScript precisa procurar em arquivos de entrada ou se apenas lê os arquivos inteiros na memória, mas em geral, para muitos formatos de arquivo, a entrada baseada em pipe pode ser mais lenta ou usar mais memória (devido à não procura soluções alternativas) do que as entradas de arquivo.

(Eu não tenho certeza, porque eu me inclino para a robustez. Eu quero que meus scripts funcionem (me dê resultados confiáveis) primeiro, e seja leve e rápido segundo. Pelos motivos listados abaixo, evitar arquivos temporários não me dá aceleração ou menor uso de recursos nos sistemas que eu uso.)

Em muitas (mais?) distribuições Linux, Solaris (desde SunOS 4 e Solaris 2.1), NetBSD (4.0 e posterior), FreeBSD (7.0 e posterior), DragonFly BSD e OpenBSD (5.5 e posterior), /tmp é geralmente um tmpfs , um sistema de arquivos baseado em RAM. Nesses sistemas, evitar arquivos temporários é, então, contraproducente (exceto nos casos em que você absolutamente sabe que os aplicativos para os quais você os alimenta podem processar a entrada como um fluxo, ou seja, por meio de um cano, sem desvantagens).

Contra-exemplos típicos (isto é, quando você usa um cano em vez de arquivos temporários) são simples filtragem ou processamento por meio de, e. sed ou awk . O GhostScript definitivamente não é "um simples programa de filtragem ou processamento".

Todos os sistemas operacionais atuais são inteligentes o suficiente para manter os arquivos usados recentemente na memória, em vez de escrevê-los e lê-los no armazenamento. (Eles normalmente salvam o conteúdo no disco uma vez, mas não o fazem, neste tipo de situações de arquivos temporários.) Então, mesmo quando /tmp não é um sistema de arquivos baseado em RAM, arquivos temporários são mantidos na memória e, no máximo, apenas gravados uma vez no disco. Isso significa que, mesmo no /tmp não baseado em RAM, os arquivos temporários são uma boa opção.

Todos juntos, acima, significa que, em casos de uso normais, você não deseja evitar arquivos temporários, especialmente quando eles são enviados para conversores ou aplicativos para processamento.

Na verdade, geralmente a razão por trás de evitar arquivos temporários é uma variante de

I don't want my scripts to leave behind unnecessary temporary files if I interrupt them, or they fail/exit with an error/do not work right.

Com Bash e mktemp utility, isso é trivial para evitar. Eu usei o seguinte idioma há vários anos:

#!/bin/bash
Work=$(mktemp -d) || exit 1
trap "cd / ; rm -rf '$Work'" EXIT

Isso cria um diretório temporário (em /tmp/ ), que será removido automaticamente quando o script sair. (O núcleo Linux coilde mktemp torna o diretório acessível apenas para o usuário proprietário; não há acesso ao grupo ou a outros, portanto, isso também é bastante seguro.)

O comando interno trap bash é formulado (por meio dessas citações específicas exatamente assim) para que, mesmo que você altere a variável de ambiente Work posteriormente, o diretório temporário correto (original) seja removido, porque a variável é expandida quando o trap é definido e não quando o trap dispara.

Após o acima, você pode usar, por exemplo,

curl 'http://www.example.com/one.pdf' > "$Work/one.pdf" || exit 1
curl 'http://www.example.com/two.pdf' > "$Work/two.pdf" || exit 1

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=combined.pdf "$Work/one.pdf" "$Work/two.pdf" || exit 1

Não há necessidade de adicionar qualquer limpeza depois disso, já que a armadilha de saída lidará com isso automaticamente - mesmo se você interromper o script usando Ctrl + C ou outro sinal.

    
por 17.10.2016 / 20:02