最近我点击了打印文件目录的命令pdf
。
mutool show file.pdf outline
我想使用一个epub
与上述格式类似的简单用法和良好结果的命令pdf
。
有这样的事吗?
答案1
.epub
文件是.zip
包含 XHTML 和 CSS 以及其他一些文件(包括图像、各种元数据文件,可能还有一个称为toc.ncx
包含目录的 XML 文件)的文件。
以下脚本用于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 个仍然满足这一假设 - 并且这些 epub 包含它只是为了与旧的阅读器系统兼容。这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
两次,以确保结果的顺序 - 这会生成一个制表符分隔的 3 列文件(这些是两个刘海之间的 sed 行中的制表符),适合电子表格导入。
再一步查找 ncx 文件有点棘手,因为使用 xml2 为每个标签和属性生成一行对我们不利:我们需要属性等于 的属性href
的值。我们可以作一点欺骗,希望原始项目全部在一行上,然后使用 grep 提取该片段,然后使用 xml2 处理它以获得 href 值。media-type
application/x-dtbncx+xml
由于这是一个相对 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 中缺少标题)