Недавно я наткнулся на команду, которая выводит оглавление файла pdf
.
mutool show file.pdf outline
Я хотел бы использовать команду для epub
форматирования с такой же простотой использования и хорошим результатом, как и приведенная выше команда для pdf
форматирования.
Есть ли что-то подобное?
решение1
.epub
файлы — это .zip
файлы, содержащие XHTML и CSS, а также некоторые другие файлы (включая изображения, различные файлы метаданных и, возможно, XML-файл, называемый , toc.ncx
содержащий оглавление).
Следующий скрипт использует unzip -p
для извлечения toc.ncx
в stdout, перенаправляет его черезxml2команду, а затем sed
извлечь только текст каждого заголовка главы.
В командной строке необходимо указать один или несколько аргументов имени файла.
#! /bin/sh
# This script needs InfoZIP's unzip program
# and the xml2 tool from http://ofb.net/~egnor/xml2/
# and sed, of course.
for f in "$@" ; do
echo "$f:"
unzip -p "$f" toc.ncx |
xml2 |
sed -n -e 's:^/ncx/navMap/navPoint/navLabel/text=: :p'
echo
done
Он выводит имя файла epub, за которым следует :
, затем делает отступ для каждого заголовка главы на два пробела в следующих строках. Например:
book.epub:
Chapter One
Chapter Two
Chapter Three
Chapter Four
Chapter Five
book2.epub:
Chapter One
Chapter Two
Chapter Three
Chapter Four
Chapter Five
Если файл epub не содержит toc.ncx
, вы увидите следующий вывод для этой конкретной книги:
book3.epub:
caution: filename not matched: toc.ncx
error: Extra content at the end of the document
Первая строка ошибки — из unzip
, вторая — из xml2
. xml2
также предупредит о других найденных ошибках — например, о неправильно отформатированном toc.ncx
файле.
Обратите внимание, что сообщения об ошибках выводятся на stderr, тогда как имя файла книги по-прежнему выводится на stdout.
xml2
доступен в предварительно упакованном виде для Debian, Ubuntu и других производных от Debian, а также, вероятно, для большинства других дистрибутивов Linux.
Для таких простых задач (например, когда вы просто хотите преобразовать XML в строчно-ориентированный формат для использования с sed
, awk
, cut
, grep
, и т. д.) xml2
проще и легче использовать, чем xmlstarlet
.
Кстати, если вы хотите также напечатать название epub-файла, измените скрипт sed
на:
sed -n -e 's:^/ncx/navMap/navPoint/navLabel/text=: :p
s!^/ncx/docTitle/text=! Title: !p'
или замените его скриптом awk
:
awk -F= '/(navLabel|docTitle)\/text/ {print $2}'
решение2
Хотя ответ, предоставленный @cas, работает в некоторых случаях, он основан на предположении о версии epub 2.0 с документом NCX, названным toc.ncx
на верхнем уровне zip-контейнера. Из 223 epub, которые у меня есть в одной папке, только 5 все еще соответствуют этому предположению — и они содержат его только для совместимости со старыми системами чтения. toc.ncx
Файл не является обязательным — единственным обязательным файлом является META-INF/content.xml
. Он будет содержать указатели на все остальные элементы epub. Это немного усложняет скриптование через bash, но возможно. Вот скрипт, который извлечет заголовок и автора из файла opf (на который указывает content.xml):
#! /bin/sh
for f in "$@" ; do
echo -n "$f"" "
opf=$(unzip -p "$f" META-INF/container.xml |
xml2 |
sed -n -e 's:^/container/rootfiles/rootfile/@full-path=::p')
unzip -p "$f" "$opf" |
xml2 |
sed -n -e 's!^/package/metadata/dc:title=! !p' | tr '
' ' '
unzip -p "$f" "$opf" |
xml2 |
sed -n -e 's!^/package/metadata/dc:creator=! !p' | tr '
' ' '
echo
done
Да, он анализирует opf
дважды, чтобы обеспечить порядок результатов — это создает файл из трех столбцов, разделенных табуляцией (это табуляции в строках sed между двумя восклицательными знаками), подходящий для импорта электронных таблиц.
Пройти еще один шаг, чтобы найти файл ncx, немного сложнее, так как использование xml2 для генерации одной строки для каждого тега и атрибута здесь работает против нас: нам нужно значение атрибута, атрибут href
которого media-type
равен application/x-dtbncx+xml
. Мы можем немного схитрить и надеяться, что исходный элемент находится на одной строке, и использовать grep для извлечения только этого фрагмента, а затем обработать его с помощью xml2, чтобы получить значение href.
Поскольку это относительный URL, нам также нужно извлечь часть пути из записи opf. Собрав все вместе, мы получаем:
#! /bin/sh
for f in "$@" ; do
echo "$f"" "
opf=$(unzip -p "$f" META-INF/container.xml |
xml2 |
sed -n -e 's:^/container/rootfiles/rootfile/@full-path=::p')
ncx=$(unzip -p "$f" "$opf" |
grep application/x-dtbncx+xml|
xml2 |
sed -n -e 's!^/item/@href=!!p')
opf_filename=${opf##*/}
opf_path=${opf%$opf_filename}
unzip -p "$f" ${opf_path}${ncx} |
xml2 |
sed -n -e 's:^/ncx/navMap/navPoint/navLabel/text=: :p
s!^/ncx/docTitle/text=!Title: !p'
done
Это все еще делает предположения, самое сильное из которых заключается в том, что это файлы, совместимые с epub2, и, следовательно, содержащие файл ncx, где-то. Документы epub3 используют другой формат навигации на основе HTML. Несмотря на это, я получаю оглавления для всех 223 моих тестовых файлов (хотя у некоторых нет заголовков в ncx)