У меня есть функция Bash для отображения справочных страниц в виде postscript, в PDF:
function psman () {
man -t "$@" | ps2pdf - /tmp/manpage.pdf
evince /tmp/manpage.pdf
}
( Обновление : я убрал периферийные сложности, такие как динамическая генерация имени временного файла и использование nohup)
Это отлично работает. Для скриншота его использования, смотрите https://www.tartley.com/postscript-formatted-man-pages .
Для собственного назидания я попытался реализовать его без использования временных файлов. Например, используя процесс подстановки:
$ evince <(man -t ls | ps2pdf - -)
Это не работает Evince отображает ошибку в своем графическом интерфейсе:
Unable to open document "file:///dev/fd/63".
PDF document is damaged
Зачем? Как я могу создавать и просматривать PDF без создания каких-либо промежуточных файлов?
Приведенное выше сообщение об ошибке отличается от сообщений, отображаемых для отсутствующих или пустых файлов, поэтому дело не только в этом.
Обновление: чтобы получить больше информации, я попытался заменить 'evince' на 'ls':
$ ls -l <(man -t ls | ps2pdf - -)
lr-x------. 1 jhartley jhartley 64 Aug 23 08:59 /dev/fd/63 -> pipe:[196475]
где дирколор красит:
/dev/fd/63
как «ORPHAN» (символическая ссылка, указывающая на несуществующий файл), иpipe:[196475]
как «MISSING» (несуществующий файл, на который указывает символическая ссылка)
Так может быть, evince просто дается ссылка, указывающая на файл, который не существует? Чтобы имитировать это, я создал символическую ссылку, которая указывает на несуществующий файл, а затем открыл его с помощью команды «evince». Но вместо сообщения «PDF поврежден», приведенного выше, появляется сообщение «Нет такого файла или каталога».
Обновление: я думаю, что типы файлов ORPHAN / MISSING - красная сельдь. Я вижу ту же символическую ссылку ORPHAN / MISSING, когда выполняю очень простую подстановку процесса:
$ ls -l <( echo 123 )
и использование того же man|ps2pdt
конвейера работает нормально, когда подстановка процесса подается на diff
:
$ diff <(man -t ls | ps2pdf - - | tr "\0" "0") <(man -t ls | ps2pdf - - | tr "\0" "0")
248c248
< /ID [<95A81B38FAE8E6FE3C899586A1DEE861><95A81B38FAE8E6FE3C899586A1DEE861>]
---
> /ID [<2F9164BD9265C8540A4A8E7068076344><2F9164BD9265C8540A4A8E7068076344>]
(Здесь я добавил 'tr' в конвейеры, чтобы исключить ноль / ноль символов в выводе pdf, чтобы diff воспринимал файлы как текстовые, а не двоичные.)
Итак, в общем, я понятия не имею, почему я получаю ошибку «PDF поврежден» выше. Моя цель, помимо понимания, состоит в том, чтобы просмотреть сгенерированный PDF, не создавая при этом никаких файлов.
evince <( cat man-ls.pdf )
открывается без ошибок, отображаются 4 страницы (правильное число), но все страницы пусты. Как будто он частично прочитал файл успешно, но затем потерпел неудачу в какой-то момент.Ответы:
Просто предположение, но правдоподобное:
evince
ищет через "файл", поток, который он получает, не доступен для поиска. Сравните Почему подстановка процесса BASH не работает с некоторыми командами?Это означает, что (почти?) Невозможно достичь того, что вы хотите, без какого-либо промежуточного файла. Лучшее, что я могу придумать, это такой скрипт:
Замечания, подводные камни и т.д .:
$tmpd
есть/dev/shm
, временный файл создается в памяти . Я предполагаю, что он настолько близок к «без создания каких-либо промежуточных файлов», насколько вы можете легко получить, сохраняя его доступным для поиска.mktemp
иrm
, файл сохраняется, и мы этого не хотим. Есть несколько подходов к этой проблеме, вы можетеtrap
сигнализировать, если хотите; Я решил запустить всю последовательность в background (( … ) &
), что может быть достаточно.evince
файл не открывается,/dev/shm
если только его имя не заканчивается.pdf
(это поведение не учитывает регистр). Вот почему есть.pdf
в шаблоне имени файла. Там нет такой проблемы в/tmp
. Зачем? Я не знаю.$*
в нем, чтобы сделать его несколько осмысленным (он отображается в заголовкеevince
окна).источник
PDF-файлы представляют собой набор взаимосвязанных объектов, идентифицируемых с помощью идентификаторов. В конце файла имеется индекс для объектов, который сопоставляет идентификаторы смещениям файла. Без этого индекса невозможно использовать PDF-файл, поэтому обычный подход к чтению PDF-файла заключается в том, чтобы приблизиться к концу и попытаться найти начало индекса, который затем считывается в память. Индекс указывает, какой объект является корневым объектом, и оттуда вы можете пройти по графу объектов, всегда используя индекс, чтобы найти смещение файла каждого связанного объекта.
Теоретически вы можете прочитать (или mmap) весь файл в память, но это не сработает с очень большими файлами, и PDF предназначен для того, чтобы справляться с действительно большими файлами (и, действительно, PDF-файлы с качеством печати могут быть действительно большой). Таким образом, поиск является неотъемлемой частью использования файла PDF, и подстановка процесса не поддерживает поиск.
Есть другие приложения командной строки, которые нужно искать или думать, что они делают. (Иногда поиск является просто попыткой программиста выяснить, насколько большой файл для удобства.) Существуют другие форматы файлов, которые ставят индекс в конце (например, сжатие Zip) и действительно полагаются на поиск. Базы данных, например, на самом деле даже не имеют смысла линейного чтения, и, вероятно, никто даже не подумает о предоставлении файла поддержки базы данных путем подстановки процесса. Но PDF - это своего рода плакат для нелинейной обработки, и это иногда удивляет.
источник
Вам нужно только добавить имя файла, например, использовать:
(man -t ls | ps2pdf - ~/man_ls.pdf) > evince
Это собирается создать
man_ls.pdf
файл в вашем домашнем каталогеисточник
cmd1 <( cmd2 )
синтаксиса. Стандартный выводcmd2
(в моем примере ps2pdf) переходит в канал, и этому каналу присваивается имя в файловой системе, и это имя передается в cmd1 (в моем примере evince). cmd1 может открыть имя файла, которое ему было дано, прочитать его и получить стандартный вывод cmd2. Ни одна из команд не имеет ни малейшего представления о том, что используется подстановка процесса. Однако Bash ни в коем случае не записывает байты на диск. Это все в памяти, очень похоже на перенаправление и каналы. Дело в производительности и личном обучении.